@arrai-innovations/reactive-helpers 1.2.3 → 2.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.
@@ -1,5 +1,5 @@
1
- import { cloneDeep, isEmpty } from "lodash";
2
- import { computed, effectScope, reactive, unref } from "vue";
1
+ import { cloneDeep } from "lodash";
2
+ import { computed, effectScope, reactive } from "vue";
3
3
  import { assignReactiveObject } from "../utils/assignReactiveObject";
4
4
  import { getFakeId } from "../utils/getFakeId";
5
5
  import inspect from "browser-util-inspect";
@@ -30,23 +30,24 @@ export function useListInstances(listInstanceArgs) {
30
30
  return instances;
31
31
  }
32
32
 
33
- export function useListInstance({ crudArgs, defaultListArgs = {}, defaultRetrieveArgs = {} }) {
33
+ export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {} }) {
34
34
  const state = reactive({
35
- listInstanceCrud: {
35
+ crud: {
36
36
  args: {},
37
37
  list: undefined,
38
38
  },
39
- defaultRetrieveArgs,
40
- defaultListArgs,
39
+ retrieveArgs,
40
+ listArgs,
41
41
  objects: {},
42
42
  loading: undefined,
43
43
  errored: false,
44
44
  error: null,
45
45
  order: [],
46
46
  });
47
- Object.assign(state.listInstanceCrud, cloneDeep(defaultCrud));
47
+ // prevent linking of all instances to the same default .args object
48
+ Object.assign(state.crud, cloneDeep(defaultCrud));
48
49
  if (crudArgs) {
49
- assignReactiveObject(state.listInstanceCrud.args, crudArgs);
50
+ assignReactiveObject(state.crud.args, crudArgs);
50
51
  }
51
52
 
52
53
  const defaultPageCallback = (newObjects) => {
@@ -59,37 +60,47 @@ export function useListInstance({ crudArgs, defaultListArgs = {}, defaultRetriev
59
60
  });
60
61
  };
61
62
 
62
- async function list({ listArgs, retrieveArgs } = {}) {
63
+ function list() {
64
+ // this function cannot be async, or the resulting promise will lose its .cancel() method
63
65
  if (state.loading) {
64
- throw new ListError("already loading.");
65
- }
66
- if (isEmpty(retrieveArgs) && !isEmpty(unref(state.defaultRetrieveArgs))) {
67
- retrieveArgs = unref(state.defaultRetrieveArgs);
68
- }
69
- if (isEmpty(listArgs) && !isEmpty(unref(state.defaultListArgs))) {
70
- listArgs = unref(state.defaultListArgs);
66
+ return Promise.reject(new ListError("already loading."));
71
67
  }
68
+ let returnPromiseResolve;
69
+ const returnPromise = new Promise((resolve) => {
70
+ returnPromiseResolve = resolve;
71
+ });
72
72
  state.loading = true;
73
73
  state.errored = false;
74
74
  state.error = null;
75
- return state.listInstanceCrud
76
- .list({
77
- crudArgs: state.listInstanceCrud.args,
78
- retrieveArgs,
79
- listArgs,
80
- pageCallback: returnedObject.pageCallback,
81
- })
75
+ const listPromise = state.crud.list({
76
+ crudArgs: state.crud.args,
77
+ retrieveArgs: state.retrieveArgs,
78
+ listArgs: state.listArgs,
79
+ pageCallback: returnedObject.pageCallback,
80
+ });
81
+ if (listPromise.cancel) {
82
+ returnPromise.cancel = async () => {
83
+ let promise = listPromise.cancel();
84
+ state.loading = false;
85
+ returnPromiseResolve(false);
86
+ if (promise) {
87
+ await promise;
88
+ }
89
+ };
90
+ }
91
+ // the indirection of promises here is to allow us to do additional work on listPromise's cancel
92
+ listPromise
82
93
  .then(() => {
83
- return Promise.resolve(true);
94
+ state.loading = false;
95
+ returnPromiseResolve(true);
84
96
  })
85
97
  .catch((error) => {
98
+ state.loading = false;
86
99
  state.errored = true;
87
100
  state.error = error;
88
- return Promise.resolve(false);
89
- })
90
- .finally(() => {
91
- state.loading = false;
101
+ returnPromiseResolve(false);
92
102
  });
103
+ return returnPromise;
93
104
  }
94
105
 
95
106
  function addListObject(object) {
@@ -1,8 +1,9 @@
1
- import { effectScope, onScopeDispose, reactive, toRef } from "vue";
1
+ import { computed, effectScope, reactive, toRef } from "vue";
2
2
  import { useListInstance } from "./listInstance";
3
3
  import { cloneDeep, isEmpty, isObject } from "lodash";
4
4
  import { assignReactiveObject } from "../utils/assignReactiveObject";
5
5
  import inspect from "browser-util-inspect";
6
+ import { useCancellableIntent } from "../utils/cancellableIntent";
6
7
 
7
8
  export class ListSubscriptionError extends Error {
8
9
  constructor(message) {
@@ -12,11 +13,13 @@ export class ListSubscriptionError extends Error {
12
13
  }
13
14
 
14
15
  const defaultCrud = {
16
+ args: {},
15
17
  subscribe: undefined,
16
18
  };
17
19
 
18
- export function setListSubscriptionCrud({ subscribe }) {
20
+ export function setListSubscriptionCrud({ subscribe, args = {} }) {
19
21
  defaultCrud.subscribe = subscribe;
22
+ Object.assign(defaultCrud.args, args);
20
23
  }
21
24
 
22
25
  export function useListSubscriptions(args, listInstances = {}) {
@@ -27,35 +30,41 @@ export function useListSubscriptions(args, listInstances = {}) {
27
30
  return subscriptions;
28
31
  }
29
32
 
30
- export function useListSubscription({ listInstance, crudArgs, defaultListArgs, defaultRetrieveArgs }) {
33
+ export function useListSubscription({ listInstance, crudArgs, listArgs, retrieveArgs }) {
31
34
  if (!listInstance) {
32
- listInstance = useListInstance({ crudArgs, defaultListArgs, defaultRetrieveArgs });
35
+ listInstance = useListInstance({ crudArgs, listArgs, retrieveArgs });
33
36
  }
34
- let cancelSubscription = null;
37
+ let subscribeIntent, listIntent;
35
38
  const state = reactive({
36
- listSubscriptionCrud: {},
39
+ crud: {
40
+ args: {},
41
+ subscribe: undefined,
42
+ },
43
+ subscriptionLoading: undefined,
44
+ subscriptionErrored: false,
45
+ subscriptionError: null,
46
+ intendToList: false,
37
47
  intendToSubscribe: false,
38
48
  });
39
- assignReactiveObject(state.listSubscriptionCrud, cloneDeep(defaultCrud));
49
+ // prevent linking of all instances to the same default .args object
50
+ Object.assign(state.crud, cloneDeep(defaultCrud));
51
+ if (crudArgs) {
52
+ assignReactiveObject(state.crud.args, crudArgs);
53
+ }
40
54
 
41
- async function subscribe({ listArgs, retrieveArgs } = {}) {
42
- if (!listArgs) {
43
- listArgs = cloneDeep(listInstance.state.defaultListArgs);
44
- }
45
- if (!retrieveArgs) {
46
- retrieveArgs = cloneDeep(listInstance.state.defaultRetrieveArgs);
55
+ function publicSubscribe({ list = true } = {}) {
56
+ let didSubscribe = false;
57
+ if (!state.intendToSubscribe) {
58
+ state.intendToSubscribe = true;
59
+ didSubscribe = true;
47
60
  }
48
- if (!cancelSubscription) {
49
- cancelSubscription = await state.listSubscriptionCrud.subscribe({
50
- crudArgs: listInstance.state.listInstanceCrud.args,
51
- listArgs,
52
- retrieveArgs,
53
- subscriptionEventCallback,
54
- });
55
- state.subscribed = true;
56
- return true;
61
+ if (list) {
62
+ if (!state.intendToList) {
63
+ state.intendToList = true;
64
+ didSubscribe = true;
65
+ }
57
66
  }
58
- return false;
67
+ return didSubscribe;
59
68
  }
60
69
 
61
70
  function subscriptionEventCallback(data, action) {
@@ -72,14 +81,17 @@ export function useListSubscription({ listInstance, crudArgs, defaultListArgs, d
72
81
  }
73
82
  }
74
83
 
75
- async function unsubscribe() {
76
- if (cancelSubscription) {
77
- const returnValue = await cancelSubscription();
78
- state.subscribed = false;
79
- cancelSubscription = null;
80
- return returnValue;
84
+ function publicUnsubscribe() {
85
+ let didUnsubscribe = false;
86
+ if (state.intendToSubscribe) {
87
+ state.intendToSubscribe = false;
88
+ didUnsubscribe = true;
81
89
  }
82
- return false;
90
+ if (state.intendToList) {
91
+ state.intendToList = false;
92
+ didUnsubscribe = true;
93
+ }
94
+ return didUnsubscribe;
83
95
  }
84
96
 
85
97
  function addFromSubscription(data) {
@@ -128,19 +140,53 @@ export function useListSubscription({ listInstance, crudArgs, defaultListArgs, d
128
140
  const es = effectScope();
129
141
 
130
142
  es.run(() => {
143
+ state.loading = computed(() => listInstance.state.loading || state.subscriptionLoading);
144
+ state.errored = computed(() => listInstance.state.errored || state.subscriptionErrored);
145
+ state.error = computed(() => listInstance.state.error || state.subscriptionError);
146
+
147
+ state.retrieveArgs = computed(() => listInstance.state.retrieveArgs);
148
+ state.listArgs = computed(() => listInstance.state.listArgs);
131
149
  state.objects = toRef(listInstance.state, "objects");
132
150
  state.order = toRef(listInstance.state, "order");
133
151
  state.objectsInOrder = toRef(listInstance.state, "objectsInOrder");
134
- onScopeDispose(async () => {
135
- await unsubscribe();
152
+
153
+ subscribeIntent = useCancellableIntent({
154
+ awaitableWithCancel: () => {
155
+ // this function cannot be async, or the resulting promise will lose its .cancel() method
156
+ const subscribePromise = state.crud.subscribe({
157
+ crudArgs: cloneDeep(state.crud.args),
158
+ listArgs: cloneDeep(listInstance.state.listArgs),
159
+ retrieveArgs: cloneDeep(listInstance.state.retrieveArgs),
160
+ subscriptionEventCallback,
161
+ });
162
+ // catching makes a new promise, we need to make sure the cancel method lives on.
163
+ const catchPromise = subscribePromise.catch((err) => {
164
+ console.error(err);
165
+ state.subscriptionErrored = true;
166
+ state.subscriptionError = err;
167
+ });
168
+ catchPromise.cancel = subscribePromise.cancel;
169
+ return catchPromise;
170
+ },
171
+ watchArguments: [toRef(state, "intendToSubscribe"), toRef(state, "listArgs"), toRef(state, "retrieveArgs")],
172
+ clearActiveOnResolved: false,
173
+ });
174
+
175
+ state.subscribed = toRef(subscribeIntent.state, "active");
176
+
177
+ listIntent = useCancellableIntent({
178
+ awaitableWithCancel: listInstance.list,
179
+ watchArguments: [toRef(state, "intendToList"), toRef(state, "listArgs"), toRef(state, "retrieveArgs")],
136
180
  });
137
181
  });
138
182
 
139
183
  return {
140
184
  state,
141
185
  listInstance,
142
- subscribe,
143
- unsubscribe,
186
+ listIntent,
187
+ subscribeIntent,
188
+ subscribe: publicSubscribe,
189
+ unsubscribe: publicUnsubscribe,
144
190
  effectScope: es,
145
191
  };
146
192
  }
@@ -1,5 +1,5 @@
1
- import { cloneDeep, isEmpty } from "lodash";
2
- import { effectScope, reactive, unref } from "vue";
1
+ import { cloneDeep } from "lodash";
2
+ import { effectScope, reactive } from "vue";
3
3
  import { assignReactiveObject } from "../utils/assignReactiveObject";
4
4
 
5
5
  export class ObjectError extends Error {
@@ -24,7 +24,7 @@ export function setObjectInstanceCrud({ retrieve, create, update, patch, delete:
24
24
  defaultCrud.update = update;
25
25
  defaultCrud.patch = patch;
26
26
  defaultCrud.delete = deleteFn;
27
- assignReactiveObject(defaultCrud.args, args);
27
+ Object.assign(defaultCrud.args, args);
28
28
  }
29
29
 
30
30
  export function useObjectInstances(instanceArgs) {
@@ -35,9 +35,9 @@ export function useObjectInstances(instanceArgs) {
35
35
  return instances;
36
36
  }
37
37
 
38
- export function useObjectInstance({ crudArgs, retrieveArgs }) {
38
+ export function useObjectInstance({ crudArgs, id, retrieveArgs }) {
39
39
  const state = reactive({
40
- objectInstanceCrud: {
40
+ crud: {
41
41
  args: {},
42
42
  retrieve: undefined,
43
43
  create: undefined,
@@ -46,32 +46,32 @@ export function useObjectInstance({ crudArgs, retrieveArgs }) {
46
46
  delete: undefined,
47
47
  },
48
48
  object: {},
49
- defaultRetrieveArgs: retrieveArgs,
49
+ id,
50
+ retrieveArgs,
50
51
  loading: undefined,
51
52
  errored: false,
52
53
  error: null,
53
54
  deleted: false,
54
55
  });
55
- assignReactiveObject(state.objectInstanceCrud, cloneDeep(defaultCrud));
56
+ // prevent linking of all instances to the same default .args object
57
+ Object.assign(state.crud, cloneDeep(defaultCrud));
56
58
  if (crudArgs) {
57
- assignReactiveObject(state.objectInstanceCrud.args, crudArgs);
59
+ assignReactiveObject(state.crud.args, crudArgs);
58
60
  }
59
61
 
60
- async function retrieve({ id, ...retrieveArgs }) {
62
+ function retrieve() {
63
+ // this function cannot be async, or the resulting promise will lose its .cancel() method
61
64
  if (state.loading) {
62
- throw new ObjectError("already loading.");
63
- }
64
- if (isEmpty(retrieveArgs) && !isEmpty(unref(state.defaultRetrieveArgs))) {
65
- retrieveArgs = unref(state.defaultRetrieveArgs);
65
+ return Promise.reject(new ObjectError("already loading."));
66
66
  }
67
67
  state.loading = true;
68
68
  state.errored = false;
69
69
  state.error = null;
70
- return state.objectInstanceCrud
70
+ return state.crud
71
71
  .retrieve({
72
- crudArgs: state.objectInstanceCrud.args,
73
- id,
74
- retrieveArgs,
72
+ crudArgs: state.crud.args,
73
+ id: state.id,
74
+ retrieveArgs: state.retrieveArgs,
75
75
  })
76
76
  .then((object) => {
77
77
  assignReactiveObject(state.object, object);
@@ -87,21 +87,18 @@ export function useObjectInstance({ crudArgs, retrieveArgs }) {
87
87
  });
88
88
  }
89
89
 
90
- async function create({ object, ...retrieveArgs }) {
90
+ async function create({ object }) {
91
91
  if (state.loading) {
92
92
  throw new ObjectError("already loading.");
93
93
  }
94
- if (isEmpty(retrieveArgs) && !isEmpty(unref(state.defaultRetrieveArgs))) {
95
- retrieveArgs = unref(state.defaultRetrieveArgs);
96
- }
97
94
  state.loading = true;
98
95
  state.errored = false;
99
96
  state.error = null;
100
- return state.objectInstanceCrud
97
+ return state.crud
101
98
  .create({
102
- crudArgs: state.objectInstanceCrud.args,
99
+ crudArgs: state.crud.args,
103
100
  object,
104
- retrieveArgs,
101
+ retrieveArgs: state.retrieveArgs,
105
102
  })
106
103
  .then((object) => {
107
104
  assignReactiveObject(state.object, object);
@@ -117,21 +114,18 @@ export function useObjectInstance({ crudArgs, retrieveArgs }) {
117
114
  });
118
115
  }
119
116
 
120
- async function update({ object, ...retrieveArgs }) {
117
+ async function update({ object }) {
121
118
  if (state.loading) {
122
119
  throw new ObjectError("already loading.");
123
120
  }
124
- if (isEmpty(retrieveArgs) && !isEmpty(unref(state.defaultRetrieveArgs))) {
125
- retrieveArgs = unref(state.defaultRetrieveArgs);
126
- }
127
121
  state.loading = true;
128
122
  state.errored = false;
129
123
  state.error = null;
130
- return state.objectInstanceCrud
124
+ return state.crud
131
125
  .update({
132
- crudArgs: state.objectInstanceCrud.args,
126
+ crudArgs: state.crud.args,
133
127
  object,
134
- retrieveArgs,
128
+ retrieveArgs: state.retrieveArgs,
135
129
  })
136
130
  .then((object) => {
137
131
  assignReactiveObject(state.object, object);
@@ -147,22 +141,19 @@ export function useObjectInstance({ crudArgs, retrieveArgs }) {
147
141
  });
148
142
  }
149
143
 
150
- async function patch({ id, partialObject, ...retrieveArgs }) {
144
+ async function patch({ partialObject }) {
151
145
  if (state.loading) {
152
146
  throw new ObjectError("already loading.");
153
147
  }
154
- if (isEmpty(retrieveArgs) && !isEmpty(unref(state.defaultRetrieveArgs))) {
155
- retrieveArgs = unref(state.defaultRetrieveArgs);
156
- }
157
148
  state.loading = true;
158
149
  state.errored = false;
159
150
  state.error = null;
160
- return state.objectInstanceCrud
151
+ return state.crud
161
152
  .patch({
162
- crudArgs: state.objectInstanceCrud.args,
163
- id,
153
+ crudArgs: state.crud.args,
154
+ id: state.id,
164
155
  partialObject,
165
- retrieveArgs,
156
+ retrieveArgs: state.retrieveArgs,
166
157
  })
167
158
  .then((object) => {
168
159
  assignReactiveObject(state.object, object);
@@ -178,17 +169,17 @@ export function useObjectInstance({ crudArgs, retrieveArgs }) {
178
169
  });
179
170
  }
180
171
 
181
- async function deleteFn(id) {
172
+ async function deleteFn() {
182
173
  if (state.loading) {
183
174
  throw new ObjectError("already loading.");
184
175
  }
185
176
  state.loading = true;
186
177
  state.errored = false;
187
178
  state.error = null;
188
- return state.objectInstanceCrud
179
+ return state.crud
189
180
  .delete({
190
- crudArgs: state.objectInstanceCrud.args,
191
- id,
181
+ crudArgs: state.crud.args,
182
+ id: state.id,
192
183
  })
193
184
  .then(() => {
194
185
  state.deleted = true;
@@ -1,7 +1,8 @@
1
- import { identity } from "lodash";
2
- import { computed, effectScope, onScopeDispose, reactive, watch } from "vue";
1
+ import { cloneDeep } from "lodash";
2
+ import { computed, effectScope, reactive, toRef } from "vue";
3
3
  import { assignReactiveObject } from "../utils/assignReactiveObject";
4
4
  import { useObjectInstance } from "./objectInstance";
5
+ import { useCancellableIntent } from "../utils/cancellableIntent";
5
6
 
6
7
  export class ObjectSubscriptionError extends Error {
7
8
  constructor(message) {
@@ -10,12 +11,14 @@ export class ObjectSubscriptionError extends Error {
10
11
  }
11
12
  }
12
13
 
13
- const defaultCrud = reactive({
14
+ const defaultCrud = {
15
+ args: {},
14
16
  subscribe: undefined,
15
- });
17
+ };
16
18
 
17
- export function setObjectSubscriptionCrud({ subscribe }) {
19
+ export function setObjectSubscriptionCrud({ subscribe, args = {} }) {
18
20
  defaultCrud.subscribe = subscribe;
21
+ Object.assign(defaultCrud.args, args);
19
22
  }
20
23
 
21
24
  export function useObjectSubscriptions(subscriptionArgs) {
@@ -27,61 +30,70 @@ export function useObjectSubscriptions(subscriptionArgs) {
27
30
  }
28
31
 
29
32
  export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveArgs = {} }) {
33
+ if (retrieveArgs && objectInstance) {
34
+ throw new ObjectSubscriptionError(
35
+ "Cannot use retrieveArgs and objectInstance together, set retrieveArgs on objectInstance instead"
36
+ );
37
+ }
30
38
  if (!objectInstance) {
31
- objectInstance = useObjectInstance({ crudArgs, retrieveArgs });
39
+ objectInstance = useObjectInstance({ crudArgs, id, retrieveArgs });
32
40
  }
33
41
  const state = reactive({
34
- objectSubscriptionCrud: {
42
+ crud: {
43
+ args: {},
35
44
  subscribe: undefined,
36
45
  },
37
46
  id,
38
- retrieveArgs,
39
47
  subscriptionLoading: undefined,
40
48
  subscriptionErrored: false,
41
49
  subscriptionError: null,
42
- subscribed: false,
50
+ subscribed: undefined,
43
51
  intendToSubscribe: false,
44
52
  intendToRetrieve: false,
45
53
  });
46
- assignReactiveObject(state.objectSubscriptionCrud, defaultCrud);
47
- let cancelSubscription;
54
+ // prevent linking of all instances to the same default .args object
55
+ Object.assign(state.crud, cloneDeep(defaultCrud));
56
+ if (crudArgs) {
57
+ assignReactiveObject(state.crud.args, crudArgs);
58
+ }
59
+
60
+ let subscribeIntent, retrieveIntent;
48
61
 
49
62
  function updateFromSubscription(data) {
50
- assignReactiveObject(objectInstance.state.object, data);
63
+ assignReactiveObject(state.object, data);
51
64
  }
52
65
 
53
66
  function deleteFromSubscription() {
54
- objectInstance.state.deleted = true;
55
- assignReactiveObject(objectInstance.state.object, {});
67
+ state.deleted = true;
68
+ assignReactiveObject(state.object, {});
56
69
  }
57
70
 
58
- async function publicSubscribe({ retrieve = true } = {}) {
71
+ function publicSubscribe({ retrieve = true } = {}) {
72
+ let didSubscribe = false;
59
73
  if (!state.intendToSubscribe) {
60
74
  state.intendToSubscribe = true;
75
+ didSubscribe = true;
61
76
  }
62
77
  if (retrieve) {
63
78
  if (!state.intendToRetrieve) {
64
79
  state.intendToRetrieve = true;
80
+ didSubscribe = true;
65
81
  }
66
82
  }
67
- return subscribe();
83
+ return didSubscribe;
68
84
  }
69
85
 
70
- async function subscribe() {
71
- if (cancelSubscription || state.subscribed) {
72
- throw new ObjectSubscriptionError("already subscribed.");
73
- }
74
- if (![state.id, state.retrieveArgs].every(identity)) {
75
- // delayed until stuff is true;
76
- return false;
86
+ function subscribe() {
87
+ // this function cannot be async, or the resulting promise will lose its .cancel() method
88
+ if (subscribeIntent.state.active || state.subscribed) {
89
+ return Promise.reject(new ObjectSubscriptionError("already subscribed or subscribing."));
77
90
  }
78
91
  state.subscriptionLoading = true;
79
92
  state.subscriptionErrored = false;
80
93
  state.subscriptionError = null;
81
94
  let subscribePromise;
82
- cancelSubscription = () => subscribePromise.cancel();
83
- subscribePromise = state.objectSubscriptionCrud.subscribe({
84
- crudArgs: objectInstance.state.objectInstanceCrud.args,
95
+ subscribePromise = state.crud.subscribe({
96
+ crudArgs: state.crud.args,
85
97
  id,
86
98
  retrieveArgs: state.retrieveArgs,
87
99
  callback: (data, action) => {
@@ -92,7 +104,14 @@ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveAr
92
104
  }
93
105
  },
94
106
  });
95
- return subscribePromise
107
+ let cancelSubscription = async () => {
108
+ let cancelPromise = subscribePromise.cancel();
109
+ cancelSubscription = null;
110
+ state.subscribed = false;
111
+ return cancelPromise;
112
+ };
113
+ // then/catch/finally makes a new promise, we need to make sure the cancel method lives on.
114
+ const catchPromise = subscribePromise
96
115
  .then(() => {
97
116
  state.subscribed = true;
98
117
  return Promise.resolve(true);
@@ -110,26 +129,21 @@ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveAr
110
129
  .finally(() => {
111
130
  state.subscriptionLoading = false;
112
131
  });
132
+ catchPromise.cancel = cancelSubscription;
133
+ return catchPromise;
113
134
  }
114
135
 
115
- async function publicUnsubscribe() {
136
+ function publicUnsubscribe() {
137
+ let didUnsubscribe = false;
116
138
  if (state.intendToSubscribe) {
117
139
  state.intendToSubscribe = false;
140
+ didUnsubscribe = true;
118
141
  }
119
142
  if (state.intendToRetrieve) {
120
143
  state.intendToRetrieve = false;
144
+ didUnsubscribe = true;
121
145
  }
122
- return unsubscribe();
123
- }
124
-
125
- async function unsubscribe() {
126
- if (cancelSubscription) {
127
- state.subscribed = false;
128
- let returnPromise = cancelSubscription();
129
- cancelSubscription = null;
130
- return returnPromise;
131
- }
132
- return false;
146
+ return didUnsubscribe;
133
147
  }
134
148
 
135
149
  const es = effectScope();
@@ -139,46 +153,27 @@ export function useObjectSubscription({ objectInstance, crudArgs, id, retrieveAr
139
153
  state.errored = computed(() => objectInstance.state.errored || state.subscriptionErrored);
140
154
  state.error = computed(() => objectInstance.state.error || state.subscriptionError);
141
155
 
142
- watch(
143
- [() => state.intendToSubscribe, () => state.id, () => state.retrieveArgs],
144
- async (newArgs, oldArgs) => {
145
- const everyNew = newArgs.every((e) => e);
146
- const everyOld = oldArgs.every((e) => e);
147
- if (everyOld) {
148
- await unsubscribe();
149
- }
150
- if (everyNew) {
151
- if (!cancelSubscription && !state.subscribed) {
152
- await subscribe().catch(console.error);
153
- }
154
- }
155
- },
156
- {
157
- deep: true,
158
- }
159
- );
156
+ state.retrieveArgs = computed(() => objectInstance.state.retrieveArgs);
157
+ state.object = toRef(objectInstance.state, "object");
158
+ state.deleted = toRef(objectInstance.state, "deleted");
160
159
 
161
- watch(
162
- [() => state.intendToRetrieve, () => state.id, () => state.retrieveArgs],
163
- async (newArgs) => {
164
- const everyNew = newArgs.every((e) => e);
165
- if (everyNew) {
166
- if (!objectInstance.state.loading) {
167
- await objectInstance.retrieve({ id: state.id, ...state.retrieveArgs }).catch(console.error);
168
- }
169
- }
170
- },
171
- { deep: true }
172
- );
160
+ subscribeIntent = useCancellableIntent({
161
+ awaitableWithCancel: subscribe,
162
+ watchArguments: [toRef(state, "intendToSubscribe"), toRef(state, "id"), toRef(state, "retrieveArgs")],
163
+ clearActiveOnResolved: false,
164
+ });
173
165
 
174
- onScopeDispose(async () => {
175
- await unsubscribe();
166
+ retrieveIntent = useCancellableIntent({
167
+ awaitableWithCancel: objectInstance.retrieve,
168
+ watchArguments: [toRef(state, "intendToRetrieve"), toRef(state, "id"), toRef(state, "retrieveArgs")],
176
169
  });
177
170
  });
178
171
 
179
172
  return {
180
173
  state,
181
174
  objectInstance,
175
+ subscribeIntent,
176
+ retrieveIntent,
182
177
  subscribe: publicSubscribe,
183
178
  unsubscribe: publicUnsubscribe,
184
179
  updateFromSubscription,