@geexcode/geex-angular 0.0.34 → 0.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -105,7 +105,7 @@ interface UiModule extends GeexModule {
105
105
  declare const ExtensionModule: Record<string, any> & {};
106
106
  type ExtensionModule = typeof ExtensionModule;
107
107
  type GeexModules<TExtensionModules extends ExtensionModule = ExtensionModule> = {
108
- init(): Promise<{
108
+ init(force?: boolean): Promise<{
109
109
  [K in keyof GeexModules<TExtensionModules>]: any;
110
110
  }>;
111
111
  tenant: TenantModule;
@@ -120,8 +120,9 @@ type GeexModule<TExtension = ExtensionModule> = {
120
120
  * A module combines both reactive state (signals) and business logic methods.
121
121
  * Concrete modules can extend this interface to expose their own signals & methods.
122
122
  * This empty base exists mainly for typing convenience and future extension.
123
+ * @param force - If true, forces re-initialization even if already initialized. Defaults to false.
123
124
  */
124
- init: () => Promise<any>;
125
+ init: (force?: boolean) => Promise<any>;
125
126
  } & TExtension;
126
127
  declare function createTenantModule(injector: Injector): TenantModule;
127
128
  declare function createAuthModule(injector: Injector): AuthModule;
package/dist/index.d.ts CHANGED
@@ -105,7 +105,7 @@ interface UiModule extends GeexModule {
105
105
  declare const ExtensionModule: Record<string, any> & {};
106
106
  type ExtensionModule = typeof ExtensionModule;
107
107
  type GeexModules<TExtensionModules extends ExtensionModule = ExtensionModule> = {
108
- init(): Promise<{
108
+ init(force?: boolean): Promise<{
109
109
  [K in keyof GeexModules<TExtensionModules>]: any;
110
110
  }>;
111
111
  tenant: TenantModule;
@@ -120,8 +120,9 @@ type GeexModule<TExtension = ExtensionModule> = {
120
120
  * A module combines both reactive state (signals) and business logic methods.
121
121
  * Concrete modules can extend this interface to expose their own signals & methods.
122
122
  * This empty base exists mainly for typing convenience and future extension.
123
+ * @param force - If true, forces re-initialization even if already initialized. Defaults to false.
123
124
  */
124
- init: () => Promise<any>;
125
+ init: (force?: boolean) => Promise<any>;
125
126
  } & TExtension;
126
127
  declare function createTenantModule(injector: Injector): TenantModule;
127
128
  declare function createAuthModule(injector: Injector): AuthModule;
package/dist/index.js CHANGED
@@ -126,21 +126,45 @@ var GQL_FEDERATE_AUTH = import_graphql_tag.default`mutation federateAuthenticate
126
126
  var GQL_ON_PUBLIC_NOTIFY = import_graphql_tag.default`subscription onPublicNotify { onPublicNotify { __typename ... on DataChangeClientNotify { dataChangeType } } }`;
127
127
  var GQL_ORGS_CACHE = import_graphql_tag.default`query orgsCache { orgs(take: 999) { items { id orgType code name parentOrgCode } } }`;
128
128
  var GQL_INIT_SETTINGS = import_graphql_tag.default`query initSettings { initSettings { id name value } }`;
129
+ function guardedSignal(innerSignal, isInitialized) {
130
+ const guard = (() => {
131
+ if (!isInitialized()) {
132
+ throw new Error(`GuardedSignal not initialized.
133
+ isInitialized: ${isInitialized.toString()}
134
+ innerSignal: ${innerSignal.toString()}
135
+ `);
136
+ }
137
+ return innerSignal();
138
+ });
139
+ if ("set" in innerSignal) {
140
+ guard.set = innerSignal.set.bind(innerSignal);
141
+ guard.update = innerSignal.update.bind(innerSignal);
142
+ }
143
+ if ("asReadonly" in innerSignal) {
144
+ guard.asReadonly = innerSignal.asReadonly.bind(innerSignal);
145
+ }
146
+ return guard;
147
+ }
129
148
  function createTenantModule(injector) {
130
- const current = (0, import_core.signal)(null);
149
+ const _current = (0, import_core.signal)(null);
150
+ let _initialized = false;
131
151
  const module2 = {
132
- init: async () => {
152
+ init: async (force = false) => {
153
+ if (_initialized && !force) {
154
+ return;
155
+ }
133
156
  try {
134
157
  const tenantCode = injector.get(import_util.CookieService).get("__tenant");
135
158
  if (tenantCode) {
136
159
  const tenantData = await module2.loadTenantData(tenantCode);
137
- current.set(tenantData ?? null);
160
+ _current.set(tenantData ?? null);
138
161
  }
162
+ _initialized = true;
139
163
  } catch (err) {
140
164
  console.error(err);
141
165
  }
142
166
  },
143
- current,
167
+ current: guardedSignal(_current, () => _initialized),
144
168
  async loadTenantData(code) {
145
169
  const res = await (0, import_rxjs.firstValueFrom)(
146
170
  injector.get(import_apollo_angular.Apollo).mutate({ mutation: GQL_CHECK_TENANT, variables: { code } })
@@ -164,17 +188,22 @@ function createTenantModule(injector) {
164
188
  return module2;
165
189
  }
166
190
  function createAuthModule(injector) {
167
- const user = (0, import_core.signal)(null);
191
+ const _user = (0, import_core.signal)(null);
192
+ let _initialized = false;
168
193
  const module2 = {
169
- init: async () => {
194
+ init: async (force = false) => {
195
+ if (_initialized && !force) {
196
+ return;
197
+ }
170
198
  try {
171
199
  const userData = await module2.loadUserData();
172
- user.set(userData ?? null);
200
+ _user.set(userData ?? null);
201
+ _initialized = true;
173
202
  } catch (err) {
174
203
  console.error(err);
175
204
  }
176
205
  },
177
- user,
206
+ user: guardedSignal(_user, () => _initialized),
178
207
  async loadUserData() {
179
208
  const oAuthService = injector.get(import_angular_oauth2_oidc.OAuthService);
180
209
  try {
@@ -203,30 +232,48 @@ function createAuthModule(injector) {
203
232
  return module2;
204
233
  }
205
234
  function createIdentityModule(injector) {
206
- const orgsSignal = (0, import_core.signal)([]);
207
- const userOwnedOrgsSignal = (0, import_core.signal)([]);
235
+ const _orgsSignal = (0, import_core.signal)([]);
236
+ const _userOwnedOrgsSignal = (0, import_core.signal)([]);
237
+ let _initialized = false;
208
238
  const module2 = {
209
- orgs: orgsSignal,
210
- userOwnedOrgs: userOwnedOrgsSignal,
211
- async init() {
239
+ orgs: guardedSignal(_orgsSignal, () => _initialized),
240
+ userOwnedOrgs: guardedSignal(_userOwnedOrgsSignal, () => _initialized),
241
+ async init(force = false) {
242
+ if (_initialized && !force) {
243
+ return;
244
+ }
212
245
  try {
213
- const orgs$ = injector.get(import_apollo_angular.Apollo).watchQuery({ query: GQL_ORGS_CACHE }).valueChanges.pipe((0, import_rxjs.map)((res) => (0, import_util.deepCopy)(res.data.orgs.items)));
214
- orgs$.subscribe((orgs) => {
215
- (0, import_core.runInInjectionContext)(injector, () => {
216
- orgsSignal.set(orgs);
217
- const userData = geex.auth.user();
218
- let allOwned = [];
219
- if (orgs?.length && userData) {
220
- if (userData.id === "000000000000000000000001") {
221
- allOwned = (0, import_util.deepCopy)(orgs);
222
- } else {
223
- const ownedCodes = userData.orgs.map((x) => x.code);
224
- allOwned = orgs.filter((o) => ownedCodes.some((code) => o.code.startsWith(code)));
225
- }
246
+ await new Promise((resolve, reject) => {
247
+ const orgs$ = injector.get(import_apollo_angular.Apollo).watchQuery({ query: GQL_ORGS_CACHE }).valueChanges.pipe((0, import_rxjs.map)((res) => (0, import_util.deepCopy)(res.data.orgs.items)));
248
+ let isFirstEmit = true;
249
+ orgs$.subscribe({
250
+ next: (orgs) => {
251
+ (0, import_core.runInInjectionContext)(injector, () => {
252
+ _orgsSignal.set(orgs);
253
+ const userData = geex.auth.user();
254
+ let allOwned = [];
255
+ if (orgs?.length && userData) {
256
+ if (userData.id === "000000000000000000000001") {
257
+ allOwned = (0, import_util.deepCopy)(orgs);
258
+ } else {
259
+ const ownedCodes = userData.orgs.map((x) => x.code);
260
+ allOwned = orgs.filter((o) => ownedCodes.some((code) => o.code.startsWith(code)));
261
+ }
262
+ }
263
+ _userOwnedOrgsSignal.set(allOwned);
264
+ if (isFirstEmit) {
265
+ isFirstEmit = false;
266
+ resolve();
267
+ }
268
+ });
269
+ },
270
+ error: (err) => {
271
+ console.error(err);
272
+ reject(err);
226
273
  }
227
- userOwnedOrgsSignal.set(allOwned);
228
274
  });
229
275
  });
276
+ _initialized = true;
230
277
  } catch (error) {
231
278
  console.error(error);
232
279
  }
@@ -235,8 +282,12 @@ function createIdentityModule(injector) {
235
282
  return module2;
236
283
  }
237
284
  function createMessagingModule(injector) {
285
+ let _initialized = false;
238
286
  const module2 = {
239
- async init() {
287
+ async init(force = false) {
288
+ if (_initialized && !force) {
289
+ return;
290
+ }
240
291
  try {
241
292
  await geex.auth.init();
242
293
  if (injector.get(import_angular_oauth2_oidc.OAuthService).hasValidAccessToken()) {
@@ -245,6 +296,7 @@ function createMessagingModule(injector) {
245
296
  module2.onPublicNotify(notify);
246
297
  });
247
298
  }
299
+ _initialized = true;
248
300
  } catch (err) {
249
301
  console.error(err);
250
302
  }
@@ -256,30 +308,40 @@ function createMessagingModule(injector) {
256
308
  return module2;
257
309
  }
258
310
  function createSettingsModule(injector) {
259
- const settingsSignal = (0, import_core.signal)([]);
311
+ const _settingsSignal = (0, import_core.signal)([]);
312
+ let _initialized = false;
260
313
  const module2 = {
261
- settings: settingsSignal,
262
- async init() {
314
+ settings: guardedSignal(_settingsSignal, () => _initialized),
315
+ async init(force = false) {
316
+ if (_initialized && !force) {
317
+ return;
318
+ }
263
319
  const res = await (0, import_rxjs.firstValueFrom)(
264
320
  injector.get(import_apollo_angular.Apollo).query({ query: GQL_INIT_SETTINGS })
265
321
  );
266
322
  const settings = res.data.initSettings;
267
- settingsSignal.set(settings);
323
+ _settingsSignal.set(settings);
324
+ _initialized = true;
268
325
  }
269
326
  };
270
327
  return module2;
271
328
  }
272
329
  function createUiModule(injector) {
273
- const fullScreenSignal = (0, import_core.signal)(false);
274
- const isMobile = (0, import_rxjs_interop.toSignal)((0, import_rxjs.fromEvent)(window, "resize").pipe(
330
+ const _fullScreenSignal = (0, import_core.signal)(false);
331
+ const _isMobile = (0, import_rxjs_interop.toSignal)((0, import_rxjs.fromEvent)(window, "resize").pipe(
275
332
  (0, import_operators.debounceTime)(200),
276
333
  (0, import_operators.switchMap)(async () => window.innerHeight / window.innerWidth >= 1.5)
277
334
  ));
335
+ let _initialized = false;
278
336
  const module2 = {
279
- fullScreen: fullScreenSignal,
280
- isMobile,
337
+ fullScreen: guardedSignal(_fullScreenSignal, () => _initialized),
338
+ isMobile: guardedSignal(_isMobile, () => _initialized),
281
339
  activeRoutedComponent: void 0,
282
- async init() {
340
+ async init(force = false) {
341
+ if (_initialized && !force) {
342
+ return;
343
+ }
344
+ _initialized = true;
283
345
  return;
284
346
  }
285
347
  };
@@ -294,13 +356,13 @@ function configGeex(injector, overrides = {}) {
294
356
  ...overrides
295
357
  };
296
358
  (0, import_core2.runInInjectionContext)(injector, () => {
297
- modules.init ?? (modules.init = async () => {
359
+ modules.init ?? (modules.init = async (force = false) => {
298
360
  const entries = Object.entries(modules).filter(([key]) => key !== "init");
299
361
  return Object.fromEntries(await Promise.all(
300
362
  entries.map(async ([key, mod]) => {
301
363
  const maybeInit = mod.init;
302
364
  try {
303
- return [key, await maybeInit()];
365
+ return [key, await maybeInit(force)];
304
366
  } catch (err) {
305
367
  console.error(err);
306
368
  return [key, null];
package/dist/index.mjs CHANGED
@@ -80,21 +80,45 @@ var GQL_FEDERATE_AUTH = gql`mutation federateAuthenticate(
80
80
  var GQL_ON_PUBLIC_NOTIFY = gql`subscription onPublicNotify { onPublicNotify { __typename ... on DataChangeClientNotify { dataChangeType } } }`;
81
81
  var GQL_ORGS_CACHE = gql`query orgsCache { orgs(take: 999) { items { id orgType code name parentOrgCode } } }`;
82
82
  var GQL_INIT_SETTINGS = gql`query initSettings { initSettings { id name value } }`;
83
+ function guardedSignal(innerSignal, isInitialized) {
84
+ const guard = (() => {
85
+ if (!isInitialized()) {
86
+ throw new Error(`GuardedSignal not initialized.
87
+ isInitialized: ${isInitialized.toString()}
88
+ innerSignal: ${innerSignal.toString()}
89
+ `);
90
+ }
91
+ return innerSignal();
92
+ });
93
+ if ("set" in innerSignal) {
94
+ guard.set = innerSignal.set.bind(innerSignal);
95
+ guard.update = innerSignal.update.bind(innerSignal);
96
+ }
97
+ if ("asReadonly" in innerSignal) {
98
+ guard.asReadonly = innerSignal.asReadonly.bind(innerSignal);
99
+ }
100
+ return guard;
101
+ }
83
102
  function createTenantModule(injector) {
84
- const current = signal(null);
103
+ const _current = signal(null);
104
+ let _initialized = false;
85
105
  const module = {
86
- init: async () => {
106
+ init: async (force = false) => {
107
+ if (_initialized && !force) {
108
+ return;
109
+ }
87
110
  try {
88
111
  const tenantCode = injector.get(CookieService).get("__tenant");
89
112
  if (tenantCode) {
90
113
  const tenantData = await module.loadTenantData(tenantCode);
91
- current.set(tenantData ?? null);
114
+ _current.set(tenantData ?? null);
92
115
  }
116
+ _initialized = true;
93
117
  } catch (err) {
94
118
  console.error(err);
95
119
  }
96
120
  },
97
- current,
121
+ current: guardedSignal(_current, () => _initialized),
98
122
  async loadTenantData(code) {
99
123
  const res = await firstValueFrom(
100
124
  injector.get(Apollo).mutate({ mutation: GQL_CHECK_TENANT, variables: { code } })
@@ -118,17 +142,22 @@ function createTenantModule(injector) {
118
142
  return module;
119
143
  }
120
144
  function createAuthModule(injector) {
121
- const user = signal(null);
145
+ const _user = signal(null);
146
+ let _initialized = false;
122
147
  const module = {
123
- init: async () => {
148
+ init: async (force = false) => {
149
+ if (_initialized && !force) {
150
+ return;
151
+ }
124
152
  try {
125
153
  const userData = await module.loadUserData();
126
- user.set(userData ?? null);
154
+ _user.set(userData ?? null);
155
+ _initialized = true;
127
156
  } catch (err) {
128
157
  console.error(err);
129
158
  }
130
159
  },
131
- user,
160
+ user: guardedSignal(_user, () => _initialized),
132
161
  async loadUserData() {
133
162
  const oAuthService = injector.get(OAuthService);
134
163
  try {
@@ -157,30 +186,48 @@ function createAuthModule(injector) {
157
186
  return module;
158
187
  }
159
188
  function createIdentityModule(injector) {
160
- const orgsSignal = signal([]);
161
- const userOwnedOrgsSignal = signal([]);
189
+ const _orgsSignal = signal([]);
190
+ const _userOwnedOrgsSignal = signal([]);
191
+ let _initialized = false;
162
192
  const module = {
163
- orgs: orgsSignal,
164
- userOwnedOrgs: userOwnedOrgsSignal,
165
- async init() {
193
+ orgs: guardedSignal(_orgsSignal, () => _initialized),
194
+ userOwnedOrgs: guardedSignal(_userOwnedOrgsSignal, () => _initialized),
195
+ async init(force = false) {
196
+ if (_initialized && !force) {
197
+ return;
198
+ }
166
199
  try {
167
- const orgs$ = injector.get(Apollo).watchQuery({ query: GQL_ORGS_CACHE }).valueChanges.pipe(map((res) => deepCopy(res.data.orgs.items)));
168
- orgs$.subscribe((orgs) => {
169
- runInInjectionContext(injector, () => {
170
- orgsSignal.set(orgs);
171
- const userData = geex.auth.user();
172
- let allOwned = [];
173
- if (orgs?.length && userData) {
174
- if (userData.id === "000000000000000000000001") {
175
- allOwned = deepCopy(orgs);
176
- } else {
177
- const ownedCodes = userData.orgs.map((x) => x.code);
178
- allOwned = orgs.filter((o) => ownedCodes.some((code) => o.code.startsWith(code)));
179
- }
200
+ await new Promise((resolve, reject) => {
201
+ const orgs$ = injector.get(Apollo).watchQuery({ query: GQL_ORGS_CACHE }).valueChanges.pipe(map((res) => deepCopy(res.data.orgs.items)));
202
+ let isFirstEmit = true;
203
+ orgs$.subscribe({
204
+ next: (orgs) => {
205
+ runInInjectionContext(injector, () => {
206
+ _orgsSignal.set(orgs);
207
+ const userData = geex.auth.user();
208
+ let allOwned = [];
209
+ if (orgs?.length && userData) {
210
+ if (userData.id === "000000000000000000000001") {
211
+ allOwned = deepCopy(orgs);
212
+ } else {
213
+ const ownedCodes = userData.orgs.map((x) => x.code);
214
+ allOwned = orgs.filter((o) => ownedCodes.some((code) => o.code.startsWith(code)));
215
+ }
216
+ }
217
+ _userOwnedOrgsSignal.set(allOwned);
218
+ if (isFirstEmit) {
219
+ isFirstEmit = false;
220
+ resolve();
221
+ }
222
+ });
223
+ },
224
+ error: (err) => {
225
+ console.error(err);
226
+ reject(err);
180
227
  }
181
- userOwnedOrgsSignal.set(allOwned);
182
228
  });
183
229
  });
230
+ _initialized = true;
184
231
  } catch (error) {
185
232
  console.error(error);
186
233
  }
@@ -189,8 +236,12 @@ function createIdentityModule(injector) {
189
236
  return module;
190
237
  }
191
238
  function createMessagingModule(injector) {
239
+ let _initialized = false;
192
240
  const module = {
193
- async init() {
241
+ async init(force = false) {
242
+ if (_initialized && !force) {
243
+ return;
244
+ }
194
245
  try {
195
246
  await geex.auth.init();
196
247
  if (injector.get(OAuthService).hasValidAccessToken()) {
@@ -199,6 +250,7 @@ function createMessagingModule(injector) {
199
250
  module.onPublicNotify(notify);
200
251
  });
201
252
  }
253
+ _initialized = true;
202
254
  } catch (err) {
203
255
  console.error(err);
204
256
  }
@@ -210,30 +262,40 @@ function createMessagingModule(injector) {
210
262
  return module;
211
263
  }
212
264
  function createSettingsModule(injector) {
213
- const settingsSignal = signal([]);
265
+ const _settingsSignal = signal([]);
266
+ let _initialized = false;
214
267
  const module = {
215
- settings: settingsSignal,
216
- async init() {
268
+ settings: guardedSignal(_settingsSignal, () => _initialized),
269
+ async init(force = false) {
270
+ if (_initialized && !force) {
271
+ return;
272
+ }
217
273
  const res = await firstValueFrom(
218
274
  injector.get(Apollo).query({ query: GQL_INIT_SETTINGS })
219
275
  );
220
276
  const settings = res.data.initSettings;
221
- settingsSignal.set(settings);
277
+ _settingsSignal.set(settings);
278
+ _initialized = true;
222
279
  }
223
280
  };
224
281
  return module;
225
282
  }
226
283
  function createUiModule(injector) {
227
- const fullScreenSignal = signal(false);
228
- const isMobile = toSignal(fromEvent(window, "resize").pipe(
284
+ const _fullScreenSignal = signal(false);
285
+ const _isMobile = toSignal(fromEvent(window, "resize").pipe(
229
286
  debounceTime(200),
230
287
  switchMap(async () => window.innerHeight / window.innerWidth >= 1.5)
231
288
  ));
289
+ let _initialized = false;
232
290
  const module = {
233
- fullScreen: fullScreenSignal,
234
- isMobile,
291
+ fullScreen: guardedSignal(_fullScreenSignal, () => _initialized),
292
+ isMobile: guardedSignal(_isMobile, () => _initialized),
235
293
  activeRoutedComponent: void 0,
236
- async init() {
294
+ async init(force = false) {
295
+ if (_initialized && !force) {
296
+ return;
297
+ }
298
+ _initialized = true;
237
299
  return;
238
300
  }
239
301
  };
@@ -248,13 +310,13 @@ function configGeex(injector, overrides = {}) {
248
310
  ...overrides
249
311
  };
250
312
  runInInjectionContext2(injector, () => {
251
- modules.init ?? (modules.init = async () => {
313
+ modules.init ?? (modules.init = async (force = false) => {
252
314
  const entries = Object.entries(modules).filter(([key]) => key !== "init");
253
315
  return Object.fromEntries(await Promise.all(
254
316
  entries.map(async ([key, mod]) => {
255
317
  const maybeInit = mod.init;
256
318
  try {
257
- return [key, await maybeInit()];
319
+ return [key, await maybeInit(force)];
258
320
  } catch (err) {
259
321
  console.error(err);
260
322
  return [key, null];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geexcode/geex-angular",
3
- "version": "0.0.34",
3
+ "version": "0.0.36",
4
4
  "description": "Angular adapter for Geex core.",
5
5
  "module": "dist/index.js",
6
6
  "main": "dist/index.cjs",