@entifix/react-integration 0.1.0-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.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/context/adapters-context/adapters-context.d.ts +4 -0
  4. package/dist/context/adapters-context/adapters-context.d.ts.map +1 -0
  5. package/dist/context/adapters-context/adapters-context.js +19 -0
  6. package/dist/context/adapters-context/adapters-context.js.map +1 -0
  7. package/dist/context/adapters-context/index.d.ts +2 -0
  8. package/dist/context/adapters-context/index.d.ts.map +1 -0
  9. package/dist/context/adapters-context/index.js +3 -0
  10. package/dist/context/adapters-context/index.js.map +1 -0
  11. package/dist/hooks/use-data-loading/index.d.ts +3 -0
  12. package/dist/hooks/use-data-loading/index.d.ts.map +1 -0
  13. package/dist/hooks/use-data-loading/index.js +4 -0
  14. package/dist/hooks/use-data-loading/index.js.map +1 -0
  15. package/dist/hooks/use-data-loading/use-data-loading.d.ts +26 -0
  16. package/dist/hooks/use-data-loading/use-data-loading.d.ts.map +1 -0
  17. package/dist/hooks/use-data-loading/use-data-loading.js +167 -0
  18. package/dist/hooks/use-data-loading/use-data-loading.js.map +1 -0
  19. package/dist/hooks/use-data-loading/use-data-loading.types.d.ts +53 -0
  20. package/dist/hooks/use-data-loading/use-data-loading.types.d.ts.map +1 -0
  21. package/dist/hooks/use-data-loading/use-data-loading.types.js +3 -0
  22. package/dist/hooks/use-data-loading/use-data-loading.types.js.map +1 -0
  23. package/dist/hooks/use-entity-form/index.d.ts +4 -0
  24. package/dist/hooks/use-entity-form/index.d.ts.map +1 -0
  25. package/dist/hooks/use-entity-form/index.js +5 -0
  26. package/dist/hooks/use-entity-form/index.js.map +1 -0
  27. package/dist/hooks/use-entity-form/use-entity-form.d.ts +31 -0
  28. package/dist/hooks/use-entity-form/use-entity-form.d.ts.map +1 -0
  29. package/dist/hooks/use-entity-form/use-entity-form.helpers.d.ts +136 -0
  30. package/dist/hooks/use-entity-form/use-entity-form.helpers.d.ts.map +1 -0
  31. package/dist/hooks/use-entity-form/use-entity-form.helpers.js +337 -0
  32. package/dist/hooks/use-entity-form/use-entity-form.helpers.js.map +1 -0
  33. package/dist/hooks/use-entity-form/use-entity-form.js +209 -0
  34. package/dist/hooks/use-entity-form/use-entity-form.js.map +1 -0
  35. package/dist/hooks/use-entity-form/use-entity-form.types.d.ts +173 -0
  36. package/dist/hooks/use-entity-form/use-entity-form.types.d.ts.map +1 -0
  37. package/dist/hooks/use-entity-form/use-entity-form.types.js +3 -0
  38. package/dist/hooks/use-entity-form/use-entity-form.types.js.map +1 -0
  39. package/dist/hooks/use-entity-link-resolver/index.d.ts +2 -0
  40. package/dist/hooks/use-entity-link-resolver/index.d.ts.map +1 -0
  41. package/dist/hooks/use-entity-link-resolver/index.js +3 -0
  42. package/dist/hooks/use-entity-link-resolver/index.js.map +1 -0
  43. package/dist/hooks/use-entity-link-resolver/use-entity-link-resolver.d.ts +17 -0
  44. package/dist/hooks/use-entity-link-resolver/use-entity-link-resolver.d.ts.map +1 -0
  45. package/dist/hooks/use-entity-link-resolver/use-entity-link-resolver.js +26 -0
  46. package/dist/hooks/use-entity-link-resolver/use-entity-link-resolver.js.map +1 -0
  47. package/dist/hooks/use-entity-link-source/index.d.ts +3 -0
  48. package/dist/hooks/use-entity-link-source/index.d.ts.map +1 -0
  49. package/dist/hooks/use-entity-link-source/index.js +4 -0
  50. package/dist/hooks/use-entity-link-source/index.js.map +1 -0
  51. package/dist/hooks/use-entity-link-source/use-entity-link-source.d.ts +25 -0
  52. package/dist/hooks/use-entity-link-source/use-entity-link-source.d.ts.map +1 -0
  53. package/dist/hooks/use-entity-link-source/use-entity-link-source.js +169 -0
  54. package/dist/hooks/use-entity-link-source/use-entity-link-source.js.map +1 -0
  55. package/dist/hooks/use-entity-link-source/use-entity-link-source.types.d.ts +49 -0
  56. package/dist/hooks/use-entity-link-source/use-entity-link-source.types.d.ts.map +1 -0
  57. package/dist/hooks/use-entity-link-source/use-entity-link-source.types.js +3 -0
  58. package/dist/hooks/use-entity-link-source/use-entity-link-source.types.js.map +1 -0
  59. package/dist/hooks/use-entity-mutation/index.d.ts +3 -0
  60. package/dist/hooks/use-entity-mutation/index.d.ts.map +1 -0
  61. package/dist/hooks/use-entity-mutation/index.js +4 -0
  62. package/dist/hooks/use-entity-mutation/index.js.map +1 -0
  63. package/dist/hooks/use-entity-mutation/use-entity-mutation.d.ts +22 -0
  64. package/dist/hooks/use-entity-mutation/use-entity-mutation.d.ts.map +1 -0
  65. package/dist/hooks/use-entity-mutation/use-entity-mutation.js +88 -0
  66. package/dist/hooks/use-entity-mutation/use-entity-mutation.js.map +1 -0
  67. package/dist/hooks/use-entity-mutation/use-entity-mutation.types.d.ts +19 -0
  68. package/dist/hooks/use-entity-mutation/use-entity-mutation.types.d.ts.map +1 -0
  69. package/dist/hooks/use-entity-mutation/use-entity-mutation.types.js +3 -0
  70. package/dist/hooks/use-entity-mutation/use-entity-mutation.types.js.map +1 -0
  71. package/dist/hooks/use-entity-record/index.d.ts +3 -0
  72. package/dist/hooks/use-entity-record/index.d.ts.map +1 -0
  73. package/dist/hooks/use-entity-record/index.js +4 -0
  74. package/dist/hooks/use-entity-record/index.js.map +1 -0
  75. package/dist/hooks/use-entity-record/use-entity-record.d.ts +21 -0
  76. package/dist/hooks/use-entity-record/use-entity-record.d.ts.map +1 -0
  77. package/dist/hooks/use-entity-record/use-entity-record.js +93 -0
  78. package/dist/hooks/use-entity-record/use-entity-record.js.map +1 -0
  79. package/dist/hooks/use-entity-record/use-entity-record.types.d.ts +22 -0
  80. package/dist/hooks/use-entity-record/use-entity-record.types.d.ts.map +1 -0
  81. package/dist/hooks/use-entity-record/use-entity-record.types.js +3 -0
  82. package/dist/hooks/use-entity-record/use-entity-record.types.js.map +1 -0
  83. package/dist/hooks/use-entity-use-cases/index.d.ts +2 -0
  84. package/dist/hooks/use-entity-use-cases/index.d.ts.map +1 -0
  85. package/dist/hooks/use-entity-use-cases/index.js +3 -0
  86. package/dist/hooks/use-entity-use-cases/index.js.map +1 -0
  87. package/dist/hooks/use-entity-use-cases/use-entity-use-cases.d.ts +25 -0
  88. package/dist/hooks/use-entity-use-cases/use-entity-use-cases.d.ts.map +1 -0
  89. package/dist/hooks/use-entity-use-cases/use-entity-use-cases.js +47 -0
  90. package/dist/hooks/use-entity-use-cases/use-entity-use-cases.js.map +1 -0
  91. package/dist/hooks/use-wizard/index.d.ts +3 -0
  92. package/dist/hooks/use-wizard/index.d.ts.map +1 -0
  93. package/dist/hooks/use-wizard/index.js +4 -0
  94. package/dist/hooks/use-wizard/index.js.map +1 -0
  95. package/dist/hooks/use-wizard/use-wizard.d.ts +19 -0
  96. package/dist/hooks/use-wizard/use-wizard.d.ts.map +1 -0
  97. package/dist/hooks/use-wizard/use-wizard.js +136 -0
  98. package/dist/hooks/use-wizard/use-wizard.js.map +1 -0
  99. package/dist/hooks/use-wizard/use-wizard.types.d.ts +87 -0
  100. package/dist/hooks/use-wizard/use-wizard.types.d.ts.map +1 -0
  101. package/dist/hooks/use-wizard/use-wizard.types.js +3 -0
  102. package/dist/hooks/use-wizard/use-wizard.types.js.map +1 -0
  103. package/dist/index.d.ts +17 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +18 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/query/combine-filtering.d.ts +11 -0
  108. package/dist/query/combine-filtering.d.ts.map +1 -0
  109. package/dist/query/combine-filtering.js +18 -0
  110. package/dist/query/combine-filtering.js.map +1 -0
  111. package/dist/query/entity-query-key.d.ts +28 -0
  112. package/dist/query/entity-query-key.d.ts.map +1 -0
  113. package/dist/query/entity-query-key.js +28 -0
  114. package/dist/query/entity-query-key.js.map +1 -0
  115. package/dist/query/query-provider.d.ts +21 -0
  116. package/dist/query/query-provider.d.ts.map +1 -0
  117. package/dist/query/query-provider.js +35 -0
  118. package/dist/query/query-provider.js.map +1 -0
  119. package/dist/reactive/event-source-channel.d.ts +22 -0
  120. package/dist/reactive/event-source-channel.d.ts.map +1 -0
  121. package/dist/reactive/event-source-channel.js +93 -0
  122. package/dist/reactive/event-source-channel.js.map +1 -0
  123. package/dist/reactive/reactive-channel.d.ts +75 -0
  124. package/dist/reactive/reactive-channel.d.ts.map +1 -0
  125. package/dist/reactive/reactive-channel.js +55 -0
  126. package/dist/reactive/reactive-channel.js.map +1 -0
  127. package/dist/reactive/use-reactive-invalidation.d.ts +10 -0
  128. package/dist/reactive/use-reactive-invalidation.d.ts.map +1 -0
  129. package/dist/reactive/use-reactive-invalidation.js +25 -0
  130. package/dist/reactive/use-reactive-invalidation.js.map +1 -0
  131. package/dist/reactive/use-transaction-settlement.d.ts +41 -0
  132. package/dist/reactive/use-transaction-settlement.d.ts.map +1 -0
  133. package/dist/reactive/use-transaction-settlement.js +123 -0
  134. package/dist/reactive/use-transaction-settlement.js.map +1 -0
  135. package/package.json +73 -0
@@ -0,0 +1,22 @@
1
+ import { EntifixError, type Entity, type EntityId } from '@entifix/core';
2
+ import type { UseEntityMutationOptions } from './use-entity-mutation.types.js';
3
+ /**
4
+ * Runs the write use-cases from a component — the mutating counterpart to
5
+ * {@link useDataLoading}.
6
+ *
7
+ * Inputs are provided as tags at call time ({@link EntityTag} for a save,
8
+ * {@link EntityIdTag} for a delete), so the use-cases stay unaware of both React
9
+ * and the transport behind `ctx`.
10
+ *
11
+ * `save` resolves to the entity the *repository* returned rather than the one
12
+ * passed in. That distinction matters: a create round-trips through the store's
13
+ * id generation, so only the returned entity is addressable.
14
+ */
15
+ export declare function useEntityMutation<TEntity extends Entity, TContext>({ saveUc, deleteUc, ctx, }: UseEntityMutationOptions<TEntity, TContext>): {
16
+ save: (entity: TEntity) => Promise<TEntity | undefined>;
17
+ remove: (id: EntityId) => Promise<boolean>;
18
+ isSaving: boolean;
19
+ isDeleting: boolean;
20
+ error: EntifixError | undefined;
21
+ };
22
+ //# sourceMappingURL=use-entity-mutation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-entity-mutation.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-mutation/use-entity-mutation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzE,OAAO,KAAK,EAEV,wBAAwB,EAEzB,MAAM,gCAAgC,CAAC;AAexC;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,MAAM,EAAE,QAAQ,EAAE,EAClE,MAAM,EACN,QAAQ,EACR,GAAG,GACJ,EAAE,wBAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC;mBAI3B,OAAO,KAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;iBAiB1C,QAAQ,KAAG,OAAO,CAAC,OAAO,CAAC;;;;EAiBzC"}
@@ -0,0 +1,88 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { EntityIdTag, EntityTag } from '@entifix/business';
3
+ import { Context, Effect } from 'effect';
4
+ import { useCallback, useReducer } from 'react';
5
+ const initialState = {
6
+ isSaving: false,
7
+ isDeleting: false,
8
+ error: undefined
9
+ };
10
+ function reducer(state, action) {
11
+ return _extends({}, state, action.set);
12
+ }
13
+ /**
14
+ * Runs the write use-cases from a component — the mutating counterpart to
15
+ * {@link useDataLoading}.
16
+ *
17
+ * Inputs are provided as tags at call time ({@link EntityTag} for a save,
18
+ * {@link EntityIdTag} for a delete), so the use-cases stay unaware of both React
19
+ * and the transport behind `ctx`.
20
+ *
21
+ * `save` resolves to the entity the *repository* returned rather than the one
22
+ * passed in. That distinction matters: a create round-trips through the store's
23
+ * id generation, so only the returned entity is addressable.
24
+ */ export function useEntityMutation({ saveUc, deleteUc, ctx }) {
25
+ const [state, dispatch] = useReducer(reducer, initialState);
26
+ const save = useCallback(async (entity)=>{
27
+ dispatch({
28
+ set: {
29
+ isSaving: true,
30
+ error: undefined
31
+ }
32
+ });
33
+ try {
34
+ const saved = await Effect.runPromise(Effect.provide(saveUc, ctx.pipe(Context.add(EntityTag, entity))));
35
+ dispatch({
36
+ set: {
37
+ isSaving: false
38
+ }
39
+ });
40
+ return saved;
41
+ } catch (error) {
42
+ dispatch({
43
+ set: {
44
+ isSaving: false,
45
+ error: error
46
+ }
47
+ });
48
+ return undefined;
49
+ }
50
+ }, [
51
+ saveUc,
52
+ ctx
53
+ ]);
54
+ const remove = useCallback(async (id)=>{
55
+ dispatch({
56
+ set: {
57
+ isDeleting: true,
58
+ error: undefined
59
+ }
60
+ });
61
+ try {
62
+ await Effect.runPromise(Effect.provide(deleteUc, ctx.pipe(Context.add(EntityIdTag, id))));
63
+ dispatch({
64
+ set: {
65
+ isDeleting: false
66
+ }
67
+ });
68
+ return true;
69
+ } catch (error) {
70
+ dispatch({
71
+ set: {
72
+ isDeleting: false,
73
+ error: error
74
+ }
75
+ });
76
+ return false;
77
+ }
78
+ }, [
79
+ deleteUc,
80
+ ctx
81
+ ]);
82
+ return _extends({}, state, {
83
+ save,
84
+ remove
85
+ });
86
+ }
87
+
88
+ //# sourceMappingURL=use-entity-mutation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-mutation/use-entity-mutation.ts"],"sourcesContent":["import { EntityIdTag, EntityTag } from '@entifix/business';\nimport { EntifixError, type Entity, type EntityId } from '@entifix/core';\nimport { Context, Effect } from 'effect';\nimport { useCallback, useReducer } from 'react';\n\nimport type {\n UseEntityMutationAction,\n UseEntityMutationOptions,\n UseEntityMutationState,\n} from './use-entity-mutation.types.js';\n\nconst initialState: UseEntityMutationState = {\n isSaving: false,\n isDeleting: false,\n error: undefined,\n};\n\nfunction reducer(\n state: UseEntityMutationState,\n action: UseEntityMutationAction,\n): UseEntityMutationState {\n return { ...state, ...action.set };\n}\n\n/**\n * Runs the write use-cases from a component — the mutating counterpart to\n * {@link useDataLoading}.\n *\n * Inputs are provided as tags at call time ({@link EntityTag} for a save,\n * {@link EntityIdTag} for a delete), so the use-cases stay unaware of both React\n * and the transport behind `ctx`.\n *\n * `save` resolves to the entity the *repository* returned rather than the one\n * passed in. That distinction matters: a create round-trips through the store's\n * id generation, so only the returned entity is addressable.\n */\nexport function useEntityMutation<TEntity extends Entity, TContext>({\n saveUc,\n deleteUc,\n ctx,\n}: UseEntityMutationOptions<TEntity, TContext>) {\n const [state, dispatch] = useReducer(reducer, initialState);\n\n const save = useCallback(\n async (entity: TEntity): Promise<TEntity | undefined> => {\n dispatch({ set: { isSaving: true, error: undefined } });\n try {\n const saved = await Effect.runPromise(\n Effect.provide(saveUc, ctx.pipe(Context.add(EntityTag, entity))),\n );\n dispatch({ set: { isSaving: false } });\n return saved;\n } catch (error) {\n dispatch({ set: { isSaving: false, error: error as EntifixError } });\n return undefined;\n }\n },\n [saveUc, ctx],\n );\n\n const remove = useCallback(\n async (id: EntityId): Promise<boolean> => {\n dispatch({ set: { isDeleting: true, error: undefined } });\n try {\n await Effect.runPromise(\n Effect.provide(deleteUc, ctx.pipe(Context.add(EntityIdTag, id))),\n );\n dispatch({ set: { isDeleting: false } });\n return true;\n } catch (error) {\n dispatch({ set: { isDeleting: false, error: error as EntifixError } });\n return false;\n }\n },\n [deleteUc, ctx],\n );\n\n return { ...state, save, remove };\n}\n"],"names":["EntityIdTag","EntityTag","Context","Effect","useCallback","useReducer","initialState","isSaving","isDeleting","error","undefined","reducer","state","action","set","useEntityMutation","saveUc","deleteUc","ctx","dispatch","save","entity","saved","runPromise","provide","pipe","add","remove","id"],"mappings":";AAAA,SAASA,WAAW,EAAEC,SAAS,QAAQ,oBAAoB;AAE3D,SAASC,OAAO,EAAEC,MAAM,QAAQ,SAAS;AACzC,SAASC,WAAW,EAAEC,UAAU,QAAQ,QAAQ;AAQhD,MAAMC,eAAuC;IAC3CC,UAAU;IACVC,YAAY;IACZC,OAAOC;AACT;AAEA,SAASC,QACPC,KAA6B,EAC7BC,MAA+B;IAE/B,OAAO,aAAKD,OAAUC,OAAOC,GAAG;AAClC;AAEA;;;;;;;;;;;CAWC,GACD,OAAO,SAASC,kBAAoD,EAClEC,MAAM,EACNC,QAAQ,EACRC,GAAG,EACyC;IAC5C,MAAM,CAACN,OAAOO,SAAS,GAAGd,WAAWM,SAASL;IAE9C,MAAMc,OAAOhB,YACX,OAAOiB;QACLF,SAAS;YAAEL,KAAK;gBAAEP,UAAU;gBAAME,OAAOC;YAAU;QAAE;QACrD,IAAI;YACF,MAAMY,QAAQ,MAAMnB,OAAOoB,UAAU,CACnCpB,OAAOqB,OAAO,CAACR,QAAQE,IAAIO,IAAI,CAACvB,QAAQwB,GAAG,CAACzB,WAAWoB;YAEzDF,SAAS;gBAAEL,KAAK;oBAAEP,UAAU;gBAAM;YAAE;YACpC,OAAOe;QACT,EAAE,OAAOb,OAAO;YACdU,SAAS;gBAAEL,KAAK;oBAAEP,UAAU;oBAAOE,OAAOA;gBAAsB;YAAE;YAClE,OAAOC;QACT;IACF,GACA;QAACM;QAAQE;KAAI;IAGf,MAAMS,SAASvB,YACb,OAAOwB;QACLT,SAAS;YAAEL,KAAK;gBAAEN,YAAY;gBAAMC,OAAOC;YAAU;QAAE;QACvD,IAAI;YACF,MAAMP,OAAOoB,UAAU,CACrBpB,OAAOqB,OAAO,CAACP,UAAUC,IAAIO,IAAI,CAACvB,QAAQwB,GAAG,CAAC1B,aAAa4B;YAE7DT,SAAS;gBAAEL,KAAK;oBAAEN,YAAY;gBAAM;YAAE;YACtC,OAAO;QACT,EAAE,OAAOC,OAAO;YACdU,SAAS;gBAAEL,KAAK;oBAAEN,YAAY;oBAAOC,OAAOA;gBAAsB;YAAE;YACpE,OAAO;QACT;IACF,GACA;QAACQ;QAAUC;KAAI;IAGjB,OAAO,aAAKN;QAAOQ;QAAMO;;AAC3B"}
@@ -0,0 +1,19 @@
1
+ import { EntityIdTag, EntityTag } from '@entifix/business';
2
+ import { EntifixError, Entity } from '@entifix/core';
3
+ import { Context, Effect } from 'effect';
4
+ export interface UseEntityMutationState {
5
+ isSaving: boolean;
6
+ isDeleting: boolean;
7
+ error: EntifixError | undefined;
8
+ }
9
+ export type UseEntityMutationAction = {
10
+ set: Partial<UseEntityMutationState>;
11
+ };
12
+ export interface UseEntityMutationOptions<TEntity extends Entity, TContext> {
13
+ /** A save use-case; the hook supplies {@link EntityTag}. */
14
+ saveUc: Effect.Effect<TEntity, EntifixError, EntityTag | TContext>;
15
+ /** A delete use-case; the hook supplies {@link EntityIdTag}. */
16
+ deleteUc: Effect.Effect<void, EntifixError, EntityIdTag | TContext>;
17
+ ctx: Context.Context<TContext>;
18
+ }
19
+ //# sourceMappingURL=use-entity-mutation.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-entity-mutation.types.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-mutation/use-entity-mutation.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzC,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,MAAM,EAAE,QAAQ;IACxE,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnE,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;IACpE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChC"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=use-entity-mutation.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-mutation/use-entity-mutation.types.ts"],"sourcesContent":["import { EntityIdTag, EntityTag } from '@entifix/business';\nimport { EntifixError, Entity } from '@entifix/core';\nimport { Context, Effect } from 'effect';\n\nexport interface UseEntityMutationState {\n isSaving: boolean;\n isDeleting: boolean;\n error: EntifixError | undefined;\n}\n\nexport type UseEntityMutationAction = {\n set: Partial<UseEntityMutationState>;\n};\n\nexport interface UseEntityMutationOptions<TEntity extends Entity, TContext> {\n /** A save use-case; the hook supplies {@link EntityTag}. */\n saveUc: Effect.Effect<TEntity, EntifixError, EntityTag | TContext>;\n /** A delete use-case; the hook supplies {@link EntityIdTag}. */\n deleteUc: Effect.Effect<void, EntifixError, EntityIdTag | TContext>;\n ctx: Context.Context<TContext>;\n}\n"],"names":[],"mappings":"AAcA,WAMC"}
@@ -0,0 +1,3 @@
1
+ export * from './use-entity-record.js';
2
+ export * from './use-entity-record.types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-record/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './use-entity-record.js';
2
+ export * from './use-entity-record.types.js';
3
+
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-record/index.ts"],"sourcesContent":["export * from './use-entity-record.js';\nexport * from './use-entity-record.types.js';\n"],"names":[],"mappings":"AAAA,cAAc,yBAAyB;AACvC,cAAc,+BAA+B"}
@@ -0,0 +1,21 @@
1
+ import { EntifixError, type Entity } from '@entifix/core';
2
+ import type { UseEntityRecordOptions } from './use-entity-record.types.js';
3
+ /**
4
+ * Loads a single entity by id — the read half of an entity form.
5
+ *
6
+ * The id is provided through {@link EntityIdTag} at call time, mirroring how
7
+ * {@link useDataLoading} provides the load request: the use-case stays
8
+ * environment-agnostic and the hook is the only place that knows it is running
9
+ * in React.
10
+ *
11
+ * When `id` is `undefined` the hook does not fetch. That is the create case —
12
+ * there is no record yet — and it is a deliberate no-op rather than an error.
13
+ */
14
+ export declare function useEntityRecord<TEntity extends Entity, TContext>({ uc, ctx, id, }: UseEntityRecordOptions<TEntity, TContext>): {
15
+ reload: () => void;
16
+ setEntity: (entity: TEntity | undefined) => void;
17
+ entity: TEntity | undefined;
18
+ isLoading: boolean;
19
+ error: EntifixError | undefined;
20
+ };
21
+ //# sourceMappingURL=use-entity-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-entity-record.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-record/use-entity-record.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAI1D,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,8BAA8B,CAAC;AAmBtC;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,EAAE,QAAQ,EAAE,EAChE,EAAE,EACF,GAAG,EACH,EAAE,GACH,EAAE,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC;;wBA8D/B,OAAO,GAAG,SAAS;;;;EAK/B"}
@@ -0,0 +1,93 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { EntityIdTag } from '@entifix/business';
3
+ import { Context, Effect } from 'effect';
4
+ import { useCallback, useEffect, useReducer, useRef, useState } from 'react';
5
+ function getInitialState() {
6
+ return {
7
+ entity: undefined,
8
+ isLoading: false,
9
+ error: undefined
10
+ };
11
+ }
12
+ function reducer(state, action) {
13
+ return _extends({}, state, action.set);
14
+ }
15
+ /**
16
+ * Loads a single entity by id — the read half of an entity form.
17
+ *
18
+ * The id is provided through {@link EntityIdTag} at call time, mirroring how
19
+ * {@link useDataLoading} provides the load request: the use-case stays
20
+ * environment-agnostic and the hook is the only place that knows it is running
21
+ * in React.
22
+ *
23
+ * When `id` is `undefined` the hook does not fetch. That is the create case —
24
+ * there is no record yet — and it is a deliberate no-op rather than an error.
25
+ */ export function useEntityRecord({ uc, ctx, id }) {
26
+ const [state, dispatch] = useReducer(reducer, getInitialState());
27
+ // Bumped to re-run the fetch on demand.
28
+ const [reloadToken, setReloadToken] = useState(0);
29
+ // Callers build `uc`/`ctx` inline, so they are fresh objects on every render.
30
+ // Holding the latest in refs keeps them out of the fetch effect's
31
+ // dependencies: keying the fetch on their identity would re-run it on every
32
+ // render, and its dispatch would render again — an unbreakable loop. The
33
+ // fetch is keyed on `id`/`reloadToken`, which is what actually selects a
34
+ // record.
35
+ const ucRef = useRef(uc);
36
+ const ctxRef = useRef(ctx);
37
+ // Refs may not be written during render; this runs before the fetch effect
38
+ // below (effects fire in declaration order), so it always sees the latest.
39
+ useEffect(()=>{
40
+ ucRef.current = uc;
41
+ ctxRef.current = ctx;
42
+ });
43
+ useEffect(()=>{
44
+ if (id == null) {
45
+ return;
46
+ }
47
+ // Guards against a slow response for a previous id landing after a newer one.
48
+ let active = true;
49
+ dispatch({
50
+ set: {
51
+ isLoading: true,
52
+ error: undefined
53
+ }
54
+ });
55
+ Effect.runPromise(Effect.provide(ucRef.current, ctxRef.current.pipe(Context.add(EntityIdTag, id)))).then((entity)=>{
56
+ if (active) {
57
+ dispatch({
58
+ set: {
59
+ entity,
60
+ isLoading: false
61
+ }
62
+ });
63
+ }
64
+ }).catch((error)=>{
65
+ if (active) {
66
+ dispatch({
67
+ set: {
68
+ error: error,
69
+ isLoading: false
70
+ }
71
+ });
72
+ }
73
+ });
74
+ return ()=>{
75
+ active = false;
76
+ };
77
+ }, [
78
+ id,
79
+ reloadToken
80
+ ]);
81
+ const reload = useCallback(()=>setReloadToken((token)=>token + 1), []);
82
+ /** Replaces the held record, e.g. with the entity a save returned. */ const setEntity = useCallback((entity)=>dispatch({
83
+ set: {
84
+ entity
85
+ }
86
+ }), []);
87
+ return _extends({}, state, {
88
+ reload,
89
+ setEntity
90
+ });
91
+ }
92
+
93
+ //# sourceMappingURL=use-entity-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-record/use-entity-record.ts"],"sourcesContent":["import { EntityIdTag } from '@entifix/business';\nimport { EntifixError, type Entity } from '@entifix/core';\nimport { Context, Effect } from 'effect';\nimport { useCallback, useEffect, useReducer, useRef, useState } from 'react';\n\nimport type {\n UseEntityRecordAction,\n UseEntityRecordOptions,\n UseEntityRecordState,\n} from './use-entity-record.types.js';\n\nfunction getInitialState<\n TEntity extends Entity,\n>(): UseEntityRecordState<TEntity> {\n return {\n entity: undefined,\n isLoading: false,\n error: undefined,\n };\n}\n\nfunction reducer<TEntity extends Entity>(\n state: UseEntityRecordState<TEntity>,\n action: UseEntityRecordAction<TEntity>,\n): UseEntityRecordState<TEntity> {\n return { ...state, ...action.set };\n}\n\n/**\n * Loads a single entity by id — the read half of an entity form.\n *\n * The id is provided through {@link EntityIdTag} at call time, mirroring how\n * {@link useDataLoading} provides the load request: the use-case stays\n * environment-agnostic and the hook is the only place that knows it is running\n * in React.\n *\n * When `id` is `undefined` the hook does not fetch. That is the create case —\n * there is no record yet — and it is a deliberate no-op rather than an error.\n */\nexport function useEntityRecord<TEntity extends Entity, TContext>({\n uc,\n ctx,\n id,\n}: UseEntityRecordOptions<TEntity, TContext>) {\n const [state, dispatch] = useReducer(\n reducer as (\n state: UseEntityRecordState<TEntity>,\n action: UseEntityRecordAction<TEntity>,\n ) => UseEntityRecordState<TEntity>,\n getInitialState<TEntity>(),\n );\n // Bumped to re-run the fetch on demand.\n const [reloadToken, setReloadToken] = useState(0);\n\n // Callers build `uc`/`ctx` inline, so they are fresh objects on every render.\n // Holding the latest in refs keeps them out of the fetch effect's\n // dependencies: keying the fetch on their identity would re-run it on every\n // render, and its dispatch would render again — an unbreakable loop. The\n // fetch is keyed on `id`/`reloadToken`, which is what actually selects a\n // record.\n const ucRef = useRef(uc);\n const ctxRef = useRef(ctx);\n\n // Refs may not be written during render; this runs before the fetch effect\n // below (effects fire in declaration order), so it always sees the latest.\n useEffect(() => {\n ucRef.current = uc;\n ctxRef.current = ctx;\n });\n\n useEffect(() => {\n if (id == null) {\n return;\n }\n\n // Guards against a slow response for a previous id landing after a newer one.\n let active = true;\n dispatch({ set: { isLoading: true, error: undefined } });\n\n Effect.runPromise(\n Effect.provide(\n ucRef.current,\n ctxRef.current.pipe(Context.add(EntityIdTag, id)),\n ),\n )\n .then(entity => {\n if (active) {\n dispatch({ set: { entity, isLoading: false } });\n }\n })\n .catch((error: unknown) => {\n if (active) {\n dispatch({ set: { error: error as EntifixError, isLoading: false } });\n }\n });\n\n return () => {\n active = false;\n };\n }, [id, reloadToken]);\n\n const reload = useCallback(() => setReloadToken(token => token + 1), []);\n\n /** Replaces the held record, e.g. with the entity a save returned. */\n const setEntity = useCallback(\n (entity: TEntity | undefined) => dispatch({ set: { entity } }),\n [],\n );\n\n return { ...state, reload, setEntity };\n}\n"],"names":["EntityIdTag","Context","Effect","useCallback","useEffect","useReducer","useRef","useState","getInitialState","entity","undefined","isLoading","error","reducer","state","action","set","useEntityRecord","uc","ctx","id","dispatch","reloadToken","setReloadToken","ucRef","ctxRef","current","active","runPromise","provide","pipe","add","then","catch","reload","token","setEntity"],"mappings":";AAAA,SAASA,WAAW,QAAQ,oBAAoB;AAEhD,SAASC,OAAO,EAAEC,MAAM,QAAQ,SAAS;AACzC,SAASC,WAAW,EAAEC,SAAS,EAAEC,UAAU,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAQ7E,SAASC;IAGP,OAAO;QACLC,QAAQC;QACRC,WAAW;QACXC,OAAOF;IACT;AACF;AAEA,SAASG,QACPC,KAAoC,EACpCC,MAAsC;IAEtC,OAAO,aAAKD,OAAUC,OAAOC,GAAG;AAClC;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASC,gBAAkD,EAChEC,EAAE,EACFC,GAAG,EACHC,EAAE,EACwC;IAC1C,MAAM,CAACN,OAAOO,SAAS,GAAGhB,WACxBQ,SAIAL;IAEF,wCAAwC;IACxC,MAAM,CAACc,aAAaC,eAAe,GAAGhB,SAAS;IAE/C,8EAA8E;IAC9E,kEAAkE;IAClE,4EAA4E;IAC5E,yEAAyE;IACzE,yEAAyE;IACzE,UAAU;IACV,MAAMiB,QAAQlB,OAAOY;IACrB,MAAMO,SAASnB,OAAOa;IAEtB,2EAA2E;IAC3E,2EAA2E;IAC3Ef,UAAU;QACRoB,MAAME,OAAO,GAAGR;QAChBO,OAAOC,OAAO,GAAGP;IACnB;IAEAf,UAAU;QACR,IAAIgB,MAAM,MAAM;YACd;QACF;QAEA,8EAA8E;QAC9E,IAAIO,SAAS;QACbN,SAAS;YAAEL,KAAK;gBAAEL,WAAW;gBAAMC,OAAOF;YAAU;QAAE;QAEtDR,OAAO0B,UAAU,CACf1B,OAAO2B,OAAO,CACZL,MAAME,OAAO,EACbD,OAAOC,OAAO,CAACI,IAAI,CAAC7B,QAAQ8B,GAAG,CAAC/B,aAAaoB,OAG9CY,IAAI,CAACvB,CAAAA;YACJ,IAAIkB,QAAQ;gBACVN,SAAS;oBAAEL,KAAK;wBAAEP;wBAAQE,WAAW;oBAAM;gBAAE;YAC/C;QACF,GACCsB,KAAK,CAAC,CAACrB;YACN,IAAIe,QAAQ;gBACVN,SAAS;oBAAEL,KAAK;wBAAEJ,OAAOA;wBAAuBD,WAAW;oBAAM;gBAAE;YACrE;QACF;QAEF,OAAO;YACLgB,SAAS;QACX;IACF,GAAG;QAACP;QAAIE;KAAY;IAEpB,MAAMY,SAAS/B,YAAY,IAAMoB,eAAeY,CAAAA,QAASA,QAAQ,IAAI,EAAE;IAEvE,oEAAoE,GACpE,MAAMC,YAAYjC,YAChB,CAACM,SAAgCY,SAAS;YAAEL,KAAK;gBAAEP;YAAO;QAAE,IAC5D,EAAE;IAGJ,OAAO,aAAKK;QAAOoB;QAAQE;;AAC7B"}
@@ -0,0 +1,22 @@
1
+ import { EntityIdTag } from '@entifix/business';
2
+ import { EntifixError, Entity, EntityId } from '@entifix/core';
3
+ import { Context, Effect } from 'effect';
4
+ export interface UseEntityRecordState<TEntity extends Entity> {
5
+ entity: TEntity | undefined;
6
+ isLoading: boolean;
7
+ error: EntifixError | undefined;
8
+ }
9
+ export type UseEntityRecordAction<TEntity extends Entity> = {
10
+ set: Partial<UseEntityRecordState<TEntity>>;
11
+ };
12
+ export interface UseEntityRecordOptions<TEntity extends Entity, TContext> {
13
+ /** A get use-case; the hook supplies {@link EntityIdTag}. */
14
+ uc: Effect.Effect<TEntity, EntifixError, EntityIdTag | TContext>;
15
+ ctx: Context.Context<TContext>;
16
+ /**
17
+ * The record to load. `undefined` means "nothing to load yet" — the create
18
+ * case — and the hook stays idle rather than fetching.
19
+ */
20
+ id: EntityId;
21
+ }
22
+ //# sourceMappingURL=use-entity-record.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-entity-record.types.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-record/use-entity-record.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzC,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM;IAC1D,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,MAAM,qBAAqB,CAAC,OAAO,SAAS,MAAM,IAAI;IAC1D,GAAG,EAAE,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;CAC7C,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,OAAO,SAAS,MAAM,EAAE,QAAQ;IACtE,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;IACjE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B;;;OAGG;IACH,EAAE,EAAE,QAAQ,CAAC;CACd"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=use-entity-record.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-record/use-entity-record.types.ts"],"sourcesContent":["import { EntityIdTag } from '@entifix/business';\nimport { EntifixError, Entity, EntityId } from '@entifix/core';\nimport { Context, Effect } from 'effect';\n\nexport interface UseEntityRecordState<TEntity extends Entity> {\n entity: TEntity | undefined;\n isLoading: boolean;\n error: EntifixError | undefined;\n}\n\nexport type UseEntityRecordAction<TEntity extends Entity> = {\n set: Partial<UseEntityRecordState<TEntity>>;\n};\n\nexport interface UseEntityRecordOptions<TEntity extends Entity, TContext> {\n /** A get use-case; the hook supplies {@link EntityIdTag}. */\n uc: Effect.Effect<TEntity, EntifixError, EntityIdTag | TContext>;\n ctx: Context.Context<TContext>;\n /**\n * The record to load. `undefined` means \"nothing to load yet\" — the create\n * case — and the hook stays idle rather than fetching.\n */\n id: EntityId;\n}\n"],"names":[],"mappings":"AAcA,WASC"}
@@ -0,0 +1,2 @@
1
+ export * from './use-entity-use-cases.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-use-cases/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './use-entity-use-cases.js';
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-use-cases/index.ts"],"sourcesContent":["export * from './use-entity-use-cases.js';\n"],"names":[],"mappings":"AAAA,cAAc,4BAA4B"}
@@ -0,0 +1,25 @@
1
+ import { type Entity, type EntityConstructor, type EntityMetadataDocument, type EntityMetadataSource } from '@entifix/core';
2
+ export interface UseEntityUseCasesResult {
3
+ /** Undefined until the document arrives; a surface renders its defaults meanwhile. */
4
+ metadata?: EntityMetadataDocument;
5
+ isLoading: boolean;
6
+ error?: unknown;
7
+ }
8
+ /**
9
+ * Reads what this caller may do with an entity, from the service.
10
+ *
11
+ * The source is a parameter rather than resolved from context because the two
12
+ * consumers reach their service differently — one through the config-driven REST
13
+ * adapters, one through a shell's own same-origin routes — and a hook that knew
14
+ * about both would have to know about neither's layer.
15
+ *
16
+ * The query key sits under `'entity-metadata'`, deliberately **outside** the
17
+ * `['entity', …]` namespace: `useReactiveInvalidation` invalidates
18
+ * `['entity', <key>]` wholesale whenever a row changes, and affordances do not
19
+ * change when a record does. Keeping it out is what stops every save refetching
20
+ * this. `staleTime: Infinity` for the same reason — the document changes with
21
+ * the deployment and the caller's grants, neither of which moves inside a
22
+ * session.
23
+ */
24
+ export declare function useEntityUseCases<TEntity extends Entity>(entityConstructor: EntityConstructor<TEntity>, source: EntityMetadataSource | undefined): UseEntityUseCasesResult;
25
+ //# sourceMappingURL=use-entity-use-cases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-entity-use-cases.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-entity-use-cases/use-entity-use-cases.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAE1B,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,uBAAuB;IACtC,sFAAsF;IACtF,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,MAAM,EACtD,iBAAiB,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAC7C,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,uBAAuB,CAyBzB"}
@@ -0,0 +1,47 @@
1
+ import { envelopeEntityName } from '@entifix/core';
2
+ import { skipToken, useQuery } from '@tanstack/react-query';
3
+ /**
4
+ * Reads what this caller may do with an entity, from the service.
5
+ *
6
+ * The source is a parameter rather than resolved from context because the two
7
+ * consumers reach their service differently — one through the config-driven REST
8
+ * adapters, one through a shell's own same-origin routes — and a hook that knew
9
+ * about both would have to know about neither's layer.
10
+ *
11
+ * The query key sits under `'entity-metadata'`, deliberately **outside** the
12
+ * `['entity', …]` namespace: `useReactiveInvalidation` invalidates
13
+ * `['entity', <key>]` wholesale whenever a row changes, and affordances do not
14
+ * change when a record does. Keeping it out is what stops every save refetching
15
+ * this. `staleTime: Infinity` for the same reason — the document changes with
16
+ * the deployment and the caller's grants, neither of which moves inside a
17
+ * session.
18
+ */ export function useEntityUseCases(entityConstructor, source) {
19
+ var _query_error;
20
+ // An **optional** source, so a caller with none to offer — a generated page
21
+ // whose service exposes no `$metadata` route — needs no placeholder to hand
22
+ // over. A hook cannot be called conditionally, so the query is always created
23
+ // and simply disabled; fetching-and-failing instead would have TanStack Query
24
+ // *retry* a rejecting promise on a loop for a capability nobody asked for.
25
+ const enabled = source !== undefined;
26
+ const query = useQuery({
27
+ queryKey: [
28
+ 'entity-metadata',
29
+ envelopeEntityName(entityConstructor)
30
+ ],
31
+ // `skipToken` rather than `enabled`, because it is what lets the closure
32
+ // keep the narrowed `source` — the `enabled` form needs a non-null
33
+ // assertion in a `queryFn` that provably never runs.
34
+ queryFn: source ? ()=>source.fetchMetadata(entityConstructor) : skipToken,
35
+ staleTime: Infinity
36
+ });
37
+ return {
38
+ metadata: query.data,
39
+ // A disabled query sits in `pending` forever, so `isLoading` would be
40
+ // permanently true and every action surface would render a skeleton that
41
+ // never resolves. Nothing is in flight when nothing was asked for.
42
+ isLoading: enabled && query.isLoading,
43
+ error: (_query_error = query.error) != null ? _query_error : undefined
44
+ };
45
+ }
46
+
47
+ //# sourceMappingURL=use-entity-use-cases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-entity-use-cases/use-entity-use-cases.ts"],"sourcesContent":["import {\n type Entity,\n type EntityConstructor,\n type EntityMetadataDocument,\n type EntityMetadataSource,\n envelopeEntityName,\n} from '@entifix/core';\nimport { skipToken, useQuery } from '@tanstack/react-query';\n\nexport interface UseEntityUseCasesResult {\n /** Undefined until the document arrives; a surface renders its defaults meanwhile. */\n metadata?: EntityMetadataDocument;\n isLoading: boolean;\n error?: unknown;\n}\n\n/**\n * Reads what this caller may do with an entity, from the service.\n *\n * The source is a parameter rather than resolved from context because the two\n * consumers reach their service differently — one through the config-driven REST\n * adapters, one through a shell's own same-origin routes — and a hook that knew\n * about both would have to know about neither's layer.\n *\n * The query key sits under `'entity-metadata'`, deliberately **outside** the\n * `['entity', …]` namespace: `useReactiveInvalidation` invalidates\n * `['entity', <key>]` wholesale whenever a row changes, and affordances do not\n * change when a record does. Keeping it out is what stops every save refetching\n * this. `staleTime: Infinity` for the same reason — the document changes with\n * the deployment and the caller's grants, neither of which moves inside a\n * session.\n */\nexport function useEntityUseCases<TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n source: EntityMetadataSource | undefined,\n): UseEntityUseCasesResult {\n // An **optional** source, so a caller with none to offer — a generated page\n // whose service exposes no `$metadata` route — needs no placeholder to hand\n // over. A hook cannot be called conditionally, so the query is always created\n // and simply disabled; fetching-and-failing instead would have TanStack Query\n // *retry* a rejecting promise on a loop for a capability nobody asked for.\n const enabled = source !== undefined;\n\n const query = useQuery({\n queryKey: ['entity-metadata', envelopeEntityName(entityConstructor)],\n // `skipToken` rather than `enabled`, because it is what lets the closure\n // keep the narrowed `source` — the `enabled` form needs a non-null\n // assertion in a `queryFn` that provably never runs.\n queryFn: source ? () => source.fetchMetadata(entityConstructor) : skipToken,\n staleTime: Infinity,\n });\n\n return {\n metadata: query.data,\n // A disabled query sits in `pending` forever, so `isLoading` would be\n // permanently true and every action surface would render a skeleton that\n // never resolves. Nothing is in flight when nothing was asked for.\n isLoading: enabled && query.isLoading,\n error: query.error ?? undefined,\n };\n}\n"],"names":["envelopeEntityName","skipToken","useQuery","useEntityUseCases","entityConstructor","source","query","enabled","undefined","queryKey","queryFn","fetchMetadata","staleTime","Infinity","metadata","data","isLoading","error"],"mappings":"AAAA,SAKEA,kBAAkB,QACb,gBAAgB;AACvB,SAASC,SAAS,EAAEC,QAAQ,QAAQ,wBAAwB;AAS5D;;;;;;;;;;;;;;;CAeC,GACD,OAAO,SAASC,kBACdC,iBAA6C,EAC7CC,MAAwC;QAwB/BC;IAtBT,4EAA4E;IAC5E,4EAA4E;IAC5E,8EAA8E;IAC9E,8EAA8E;IAC9E,2EAA2E;IAC3E,MAAMC,UAAUF,WAAWG;IAE3B,MAAMF,QAAQJ,SAAS;QACrBO,UAAU;YAAC;YAAmBT,mBAAmBI;SAAmB;QACpE,yEAAyE;QACzE,mEAAmE;QACnE,qDAAqD;QACrDM,SAASL,SAAS,IAAMA,OAAOM,aAAa,CAACP,qBAAqBH;QAClEW,WAAWC;IACb;IAEA,OAAO;QACLC,UAAUR,MAAMS,IAAI;QACpB,sEAAsE;QACtE,yEAAyE;QACzE,mEAAmE;QACnEC,WAAWT,WAAWD,MAAMU,SAAS;QACrCC,KAAK,GAAEX,eAAAA,MAAMW,KAAK,YAAXX,eAAeE;IACxB;AACF"}
@@ -0,0 +1,3 @@
1
+ export * from './use-wizard.js';
2
+ export * from './use-wizard.types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-wizard/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './use-wizard.js';
2
+ export * from './use-wizard.types.js';
3
+
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/use-wizard/index.ts"],"sourcesContent":["export * from './use-wizard.js';\nexport * from './use-wizard.types.js';\n"],"names":[],"mappings":"AAAA,cAAc,kBAAkB;AAChC,cAAc,wBAAwB"}
@@ -0,0 +1,19 @@
1
+ import type { UseWizardOptions, UseWizardResult } from './use-wizard.types.js';
2
+ /**
3
+ * Drives one wizard: where the operator is, what they have answered, and the
4
+ * per-step draft each form step edits.
5
+ *
6
+ * **The draft lives here, above the forms.** A form step calls `useEntityForm`
7
+ * itself — React's hook count must stay fixed, so N form steps cannot be N hook
8
+ * calls in one component — and it unmounts when it is not the active step. What
9
+ * makes Back safe is therefore not keeping the step mounted but keeping its
10
+ * values out of it: {@link UseWizardResult.draftStoreFor} hands the step an
11
+ * `EntityDraftStore` viewing this state, and the step is free to come and go
12
+ * ([ADR 0045](../../../../../../../docs/adr/0045-the-wizard-a-step-graph-and-a-submit-that-hands-off.md)).
13
+ *
14
+ * It holds no router and performs no submit. `onStepChange` reports where the
15
+ * operator went so a shell can write the URL, and finishing is the host's — this
16
+ * hook does not know a transaction exists.
17
+ */
18
+ export declare function useWizard({ definition, draft, errored, onStepChange, }: UseWizardOptions): UseWizardResult;
19
+ //# sourceMappingURL=use-wizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-wizard.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-wizard/use-wizard.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,UAAU,EACV,KAAK,EACL,OAAO,EACP,YAAY,GACb,EAAE,gBAAgB,GAAG,eAAe,CAoIpC"}
@@ -0,0 +1,136 @@
1
+ 'use client';
2
+ import { _ as _extends } from "@swc/helpers/_/_extends";
3
+ import { advanceWizard, canFinish as canFinishWizard, emptyWizardState, entryStep, goBackWizard, goToWizardStep, stepStatuses, withStepValue } from '@entifix/core';
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ /**
6
+ * Drives one wizard: where the operator is, what they have answered, and the
7
+ * per-step draft each form step edits.
8
+ *
9
+ * **The draft lives here, above the forms.** A form step calls `useEntityForm`
10
+ * itself — React's hook count must stay fixed, so N form steps cannot be N hook
11
+ * calls in one component — and it unmounts when it is not the active step. What
12
+ * makes Back safe is therefore not keeping the step mounted but keeping its
13
+ * values out of it: {@link UseWizardResult.draftStoreFor} hands the step an
14
+ * `EntityDraftStore` viewing this state, and the step is free to come and go
15
+ * ([ADR 0045](../../../../../../../docs/adr/0045-the-wizard-a-step-graph-and-a-submit-that-hands-off.md)).
16
+ *
17
+ * It holds no router and performs no submit. `onStepChange` reports where the
18
+ * operator went so a shell can write the URL, and finishing is the host's — this
19
+ * hook does not know a transaction exists.
20
+ */ export function useWizard({ definition, draft, errored, onStepChange }) {
21
+ const entry = useMemo(()=>entryStep(definition), [
22
+ definition
23
+ ]);
24
+ const [state, setState] = useState(()=>emptyWizardState(entry.id));
25
+ const [isResumed, setResumed] = useState(false);
26
+ /**
27
+ * The state as of the last commit, mirrored so a handler can read it without
28
+ * a stale closure **and without doing its work inside a `setState` updater** —
29
+ * an updater runs twice under StrictMode, which would fire `onStepChange`
30
+ * and the persistence write twice per advance.
31
+ */ const stateRef = useRef(state);
32
+ const touched = useRef(false);
33
+ const adopted = useRef(false);
34
+ const save = draft == null ? void 0 : draft.save;
35
+ const persisted = draft == null ? void 0 : draft.state;
36
+ const commit = useCallback((updated)=>{
37
+ const current = stateRef.current;
38
+ if (updated === current) return;
39
+ touched.current = true;
40
+ stateRef.current = updated;
41
+ setState(updated);
42
+ save == null ? void 0 : save(updated);
43
+ if (updated.activeStep !== current.activeStep) {
44
+ // Resuming is a fact about arriving. Once the operator moves, the recap
45
+ // has been read or ignored, and a banner that never leaves stops being
46
+ // read at all.
47
+ setResumed(false);
48
+ onStepChange == null ? void 0 : onStepChange(updated.activeStep);
49
+ }
50
+ }, [
51
+ save,
52
+ onStepChange
53
+ ]);
54
+ const apply = useCallback((next)=>commit(next(stateRef.current)), [
55
+ commit
56
+ ]);
57
+ /**
58
+ * A persisted wizard is adopted **once, and only while untouched**.
59
+ *
60
+ * The store hydrates from an effect (`skipHydration`, ADR 0032), so it arrives
61
+ * after the first render and cannot be a `useState` initializer. Adopting it
62
+ * more than once would let a later hydration overwrite what the operator has
63
+ * since typed, and adopting it after a first edit would do the same on the
64
+ * very first keystroke.
65
+ */ useEffect(()=>{
66
+ if (adopted.current || touched.current || persisted === undefined) return;
67
+ adopted.current = true;
68
+ stateRef.current = persisted;
69
+ setState(persisted);
70
+ // Only a wizard that was genuinely mid-flow is a resume; one persisted on
71
+ // its first step has nothing to recap.
72
+ setResumed(persisted.history.length > 0);
73
+ }, [
74
+ persisted
75
+ ]);
76
+ /**
77
+ * One draft store per step id, minted once and kept forever.
78
+ *
79
+ * `useEntityForm` writes from an effect keyed on `save`, so a new identity per
80
+ * render would make every render a write. A `Map` in a ref rather than a memo
81
+ * because the set of steps a caller asks for grows as the flow is walked, and
82
+ * a memo keyed on that set would rebuild every entry whenever one was added.
83
+ */ const stores = useRef(new Map());
84
+ const draftStoreFor = useCallback((stepId)=>{
85
+ let store = stores.current.get(stepId);
86
+ if (store === undefined) {
87
+ store = {
88
+ save: (values)=>apply((current)=>withStepValue(current, stepId, {
89
+ kind: 'form',
90
+ values
91
+ })),
92
+ clear: ()=>apply((current)=>withStepValue(current, stepId, {
93
+ kind: 'none'
94
+ }))
95
+ };
96
+ stores.current.set(stepId, store);
97
+ }
98
+ const value = state.steps[stepId];
99
+ return _extends({}, (value == null ? void 0 : value.kind) === 'form' ? {
100
+ draft: value.values
101
+ } : {}, {
102
+ save: store.save,
103
+ clear: store.clear
104
+ });
105
+ }, [
106
+ apply,
107
+ state
108
+ ]);
109
+ return {
110
+ state,
111
+ activeStep: state.activeStep,
112
+ steps: stepStatuses(definition, state, errored),
113
+ canFinish: canFinishWizard(definition, state),
114
+ isResumed,
115
+ draftStoreFor,
116
+ setStepValue: useCallback((stepId, value)=>apply((current)=>withStepValue(current, stepId, value)), [
117
+ apply
118
+ ]),
119
+ next: useCallback(()=>apply((current)=>advanceWizard(definition, current)), [
120
+ apply,
121
+ definition
122
+ ]),
123
+ previous: useCallback(()=>apply(goBackWizard), [
124
+ apply
125
+ ]),
126
+ goTo: useCallback((stepId)=>apply((current)=>goToWizardStep(current, stepId)), [
127
+ apply
128
+ ]),
129
+ reset: useCallback(()=>apply(()=>emptyWizardState(entry.id)), [
130
+ apply,
131
+ entry
132
+ ])
133
+ };
134
+ }
135
+
136
+ //# sourceMappingURL=use-wizard.js.map