@noy-db/in-pinia 0.2.0-pre.3 → 0.2.0-pre.31

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.ts CHANGED
@@ -1,8 +1,18 @@
1
1
  import * as pinia from 'pinia';
2
2
  import { StateTree, PiniaPlugin } from 'pinia';
3
3
  import { ShallowRef, Ref, ComputedRef } from 'vue';
4
- import { Query, Noydb, StandardSchemaV1, Vault, NoydbStore as NoydbStore$1, NoydbOptions, Role } from '@noy-db/hub';
4
+ import { Query, Noydb, StandardSchemaV1, Vault, I18nTextDescriptor, DictKeyDescriptor, NoydbStore as NoydbStore$1, NoydbOptions, Role } from '@noy-db/hub';
5
5
 
6
+ /**
7
+ * i18n resolution mode for a store's reads.
8
+ * - `'raw'` (default) — items keep `{ [locale]: string }` maps (today's behavior).
9
+ * - `'follow'` — resolve to the global `useNoydbI18n` locale; re-read on flip.
10
+ * - `{ locale, fallback? }` — pin to a fixed locale or own ref.
11
+ */
12
+ type NoydbStoreI18nMode = 'raw' | 'follow' | {
13
+ locale: string | Ref<string>;
14
+ fallback?: string | readonly string[];
15
+ };
6
16
  /**
7
17
  * Reactive handle returned by `store.liveQuery(fn)`. Mirrors a hub
8
18
  * `LiveQuery<R>` into Vue refs; `items` updates on every left- or
@@ -24,8 +34,22 @@ interface NoydbLiveQuery<R> {
24
34
  * for full type safety.
25
35
  */
26
36
  interface NoydbStoreOptions<T> {
27
- /** Vault (tenant) name. */
28
- vault: string;
37
+ /**
38
+ * Vault (tenant) name, or a **resolver** evaluated at access time for
39
+ * federation routing (#383). A plain `string` binds the store to one
40
+ * vault for its lifetime (unchanged behavior). A `() => string` resolver
41
+ * is re-evaluated on every read/write and whenever its reactive
42
+ * dependencies change — so a store can follow the app's active scope into
43
+ * a per-client shard vault (e.g. `() => firm.shardVaultId(clientCode.value)`).
44
+ *
45
+ * When the resolved name changes, the store re-opens the new vault and
46
+ * re-hydrates `items` (mirrors the `i18n: 'follow'` re-read). If the
47
+ * resolver reads Vue reactive state, the re-hydrate is automatic; if it
48
+ * reads non-reactive state, the next `refresh()`/`add()`/`remove()`
49
+ * re-binds. Note: an in-flight `liveQuery()` handle stays bound to the
50
+ * vault it was created against — recreate it after a vault change.
51
+ */
52
+ vault: string | (() => string);
29
53
  /** Collection name within the vault. Defaults to the store id. */
30
54
  collection?: string;
31
55
  /**
@@ -60,6 +84,42 @@ interface NoydbStoreOptions<T> {
60
84
  * `@noy-db/attestation` `AttestationFieldSchema`. Stores without it behave as before.
61
85
  */
62
86
  attestation?: NonNullable<Parameters<Vault['collection']>[1]>['attestation'];
87
+ /**
88
+ * If true, the collection persists a JSON Schema baseline of `schema` so the
89
+ * schema-update protocol can detect drift on later opens. Forwarded as-is to
90
+ * the underlying `Collection`. Required for `schemaUpdate` to take effect.
91
+ */
92
+ persistJsonSchema?: NonNullable<Parameters<Vault['collection']>[1]>['persistJsonSchema'];
93
+ /**
94
+ * Ordered schema-update strategies (e.g. `coordinatedCutover`, `additiveOnly`,
95
+ * `lockSchema`) applied when a stored baseline differs from the current
96
+ * `schema`. Forwarded as-is to the underlying `Collection`. Requires
97
+ * `persistJsonSchema: true` (drift detection needs the persisted baseline).
98
+ * Lets a `defineNoydbStore`-defined collection opt into migration tracking
99
+ * declaratively, without a pre-registration `vault.collection(...)` call.
100
+ */
101
+ schemaUpdate?: NonNullable<Parameters<Vault['collection']>[1]>['schemaUpdate'];
102
+ /**
103
+ * Per-field `i18nText()` descriptors. Forwarded to the underlying
104
+ * `Collection` so locale resolution and required-translation validation
105
+ * run declaratively without a separate `vault.collection(name, { i18nFields })`
106
+ * pre-registration call.
107
+ */
108
+ i18nFields?: Record<string, I18nTextDescriptor>;
109
+ /**
110
+ * Per-field `dictKey()` descriptors. Forwarded to the underlying
111
+ * `Collection` so dictionary label resolution runs declaratively.
112
+ */
113
+ dictKeyFields?: Record<string, DictKeyDescriptor>;
114
+ /**
115
+ * How the store resolves i18nText/dictKey fields on read.
116
+ * Default `'raw'` — items keep `{ [locale]: string }` maps (today's
117
+ * behavior; zero breaking change). `'follow'` resolves to the global
118
+ * `useNoydbI18n` locale and re-reads when it changes. `{ locale }`
119
+ * pins to a fixed locale or own ref. Set `'raw'` for stores whose maps
120
+ * feed identity/export reads or a per-cell bilingual toggle.
121
+ */
122
+ i18n?: NoydbStoreI18nMode;
63
123
  }
64
124
  /**
65
125
  * The runtime shape of the store returned by `defineNoydbStore`.
@@ -153,6 +213,150 @@ declare function getActiveNoydb(): Noydb | null;
153
213
  */
154
214
  declare function resolveNoydb(explicit?: Noydb | null): Noydb;
155
215
 
216
+ /** Minimal vault shape needed to sync an ambient locale. */
217
+ interface LocaleSyncable {
218
+ setLocale(locale: string | undefined): void;
219
+ }
220
+ interface SetLocaleOptions {
221
+ /**
222
+ * Vault(s) to ALSO update via `vault.setLocale` (opt-in). Omit to keep
223
+ * the operation state-only — the safe default for locale-less vaults.
224
+ */
225
+ readonly syncVault?: LocaleSyncable | readonly LocaleSyncable[];
226
+ }
227
+ declare const useNoydbI18n: pinia.StoreDefinition<"noydb-i18n", Pick<{
228
+ locale: Ref<string, string>;
229
+ fallback: Ref<string[], string[]>;
230
+ setLocale: (l: string, opts?: SetLocaleOptions) => void;
231
+ setFallback: (chain: string[]) => void;
232
+ bindTo: (source: Ref<string>, opts?: {
233
+ immediate?: boolean;
234
+ }) => () => void;
235
+ }, "locale" | "fallback">, Pick<{
236
+ locale: Ref<string, string>;
237
+ fallback: Ref<string[], string[]>;
238
+ setLocale: (l: string, opts?: SetLocaleOptions) => void;
239
+ setFallback: (chain: string[]) => void;
240
+ bindTo: (source: Ref<string>, opts?: {
241
+ immediate?: boolean;
242
+ }) => () => void;
243
+ }, never>, Pick<{
244
+ locale: Ref<string, string>;
245
+ fallback: Ref<string[], string[]>;
246
+ setLocale: (l: string, opts?: SetLocaleOptions) => void;
247
+ setFallback: (chain: string[]) => void;
248
+ bindTo: (source: Ref<string>, opts?: {
249
+ immediate?: boolean;
250
+ }) => () => void;
251
+ }, "setLocale" | "setFallback" | "bindTo">>;
252
+
253
+ /**
254
+ * `useI18nField` — a reactive `pickLang` for a single i18nText map.
255
+ *
256
+ * Resolves a `{ [locale]: string }` map to the active locale, recomputing
257
+ * when the locale (or a reactive source) changes. Uses hub's
258
+ * `resolveI18nText` with `policy: 'null'`, so it never throws and never
259
+ * yields `undefined` — `null` when no locale (and no fallback) resolves.
260
+ *
261
+ * Follows the global `useNoydbI18n` locale/fallback unless overridden.
262
+ * Ideal for resolving one field at the edge while siblings stay raw
263
+ * (e.g. a bilingual section reading raw maps).
264
+ *
265
+ * @public
266
+ */
267
+
268
+ type MapSource = Record<string, string> | (() => Record<string, string> | undefined | null);
269
+ interface UseI18nFieldOptions {
270
+ /** Override the active locale (string or ref). Defaults to the global. */
271
+ readonly locale?: string | Ref<string>;
272
+ /** Override the fallback chain. Defaults to the global. */
273
+ readonly fallback?: string | readonly string[];
274
+ }
275
+ declare function useI18nField(source: MapSource, opts?: UseI18nFieldOptions): Ref<string | null>;
276
+
277
+ /**
278
+ * `useDictLabel(name, options)` — Vue composable for rendering
279
+ * `dictKey` fields at template time.
280
+ *
281
+ * The i18n boundary pattern has records store a **stable key**; the
282
+ * label lives in a reserved `_dict_<name>` collection and is resolved
283
+ * at render time. Every Vue / Nuxt consumer ends up writing the same
284
+ * wrapper — this composable replaces that boilerplate.
285
+ *
286
+ * ```vue
287
+ * <script setup lang="ts">
288
+ * import { useDictLabel } from '@noy-db/in-pinia'
289
+ * const label = useDictLabel('invoiceStatus')
290
+ * </script>
291
+ *
292
+ * <template>
293
+ * <td v-for="inv in invoices" :key="inv.id">
294
+ * {{ label(inv.status).value }}
295
+ * </td>
296
+ * </template>
297
+ * ```
298
+ *
299
+ * ## Reactivity
300
+ *
301
+ * `label(key)` returns a `Ref<string>` that updates when the locale
302
+ * changes (via the passed-in `locale` ref).
303
+ *
304
+ * **Known limitation:** mutations via `vault.dictionary(name).put()`
305
+ * bypass the Collection emitter — the hub's `DictionaryHandle` writes
306
+ * through the adapter directly, so labels cached by this composable
307
+ * won't refresh for those writes until either (a) the locale changes
308
+ * or (b) the caller re-creates the composable. Tracked as a
309
+ * hub follow-up (route dict writes through the Collection emitter).
310
+ *
311
+ * The underlying fetch is async, so a newly-constructed label starts
312
+ * at its "missing" sentinel (the key itself by default) and updates
313
+ * to the resolved string within one tick.
314
+ *
315
+ * @module
316
+ */
317
+
318
+ interface UseDictLabelOptions {
319
+ /**
320
+ * Explicit vault. Either a `Vault` instance or its name. When a
321
+ * name is provided the composable calls `db.vault(name)` — which
322
+ * requires the vault to already be open via
323
+ * `await db.openVault(name)` elsewhere.
324
+ *
325
+ * When omitted, uses the currently-active vault on the global
326
+ * Noydb instance set via `setActiveNoydb()`. If no vault is open
327
+ * and none is provided, setup throws.
328
+ */
329
+ readonly vault?: Vault | string;
330
+ /**
331
+ * Active locale. Pass a `Ref<string>` for live reactivity
332
+ * (e.g. `useI18n().locale` from vue-i18n, or `useLocale()` from a
333
+ * Nuxt module). A bare string is wrapped in a static ref.
334
+ * Defaults to `'en'`.
335
+ */
336
+ readonly locale?: Ref<string> | string;
337
+ /**
338
+ * Fallback locale chain — evaluated in order when the primary
339
+ * locale has no translation. Use `'any'` as the final entry to
340
+ * accept any available locale. Defaults to `['en', 'any']`.
341
+ */
342
+ readonly fallback?: string | readonly string[];
343
+ /**
344
+ * What to render when the key is absent from the dictionary.
345
+ *
346
+ * - `'key'` (default) — return the key itself. Matches the hub's
347
+ * stable-key invariant and surfaces typos during development.
348
+ * - `'empty'` — return `''`. Best for cells where a missing
349
+ * value should render blank.
350
+ * - `'placeholder'` — return `⟨missing:{key}⟩` for visible
351
+ * audit during QA.
352
+ */
353
+ readonly onMissing?: 'key' | 'empty' | 'placeholder';
354
+ }
355
+ /**
356
+ * Build a reactive label lookup. Returns a factory `(key) => Ref<string>`.
357
+ */
358
+ declare function useDictLabel(dictionaryName: string, options?: UseDictLabelOptions): (key: string) => Ref<string>;
359
+
156
360
  /**
157
361
  * `createNoydbPiniaPlugin` — augmentation path for existing Pinia stores.
158
362
  *
@@ -415,4 +619,4 @@ interface UseCapabilityGrantReturn {
415
619
  */
416
620
  declare function useCapabilityGrant(capability: string, options: UseCapabilityGrantOptions): UseCapabilityGrantReturn;
417
621
 
418
- export { CAPABILITY_REQUESTS_COLLECTION, type CapabilityGrantRecord, type CapabilityGrantState, type NoydbLiveQuery, type NoydbPiniaPluginOptions, type NoydbStore, type NoydbStoreOptions, type StoreNoydbOptions, type UseCapabilityGrantOptions, type UseCapabilityGrantReturn, createNoydbPiniaPlugin, defineNoydbStore, getActiveNoydb, resolveNoydb, setActiveNoydb, useCapabilityGrant };
622
+ export { CAPABILITY_REQUESTS_COLLECTION, type CapabilityGrantRecord, type CapabilityGrantState, type LocaleSyncable, type NoydbLiveQuery, type NoydbPiniaPluginOptions, type NoydbStore, type NoydbStoreOptions, type SetLocaleOptions, type StoreNoydbOptions, type UseCapabilityGrantOptions, type UseCapabilityGrantReturn, type UseDictLabelOptions, type UseI18nFieldOptions, createNoydbPiniaPlugin, defineNoydbStore, getActiveNoydb, resolveNoydb, setActiveNoydb, useCapabilityGrant, useDictLabel, useI18nField, useNoydbI18n };
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  // src/defineNoydbStore.ts
2
- import { defineStore } from "pinia";
2
+ import { defineStore as defineStore2 } from "pinia";
3
3
  import {
4
4
  computed,
5
5
  getCurrentScope,
6
6
  onScopeDispose,
7
- ref,
8
- shallowRef
7
+ isRef,
8
+ ref as ref2,
9
+ shallowRef,
10
+ watch as watch2
9
11
  } from "vue";
10
12
 
11
13
  // src/context.ts
@@ -24,28 +26,80 @@ function resolveNoydb(explicit) {
24
26
  );
25
27
  }
26
28
 
29
+ // src/useNoydbI18n.ts
30
+ import { defineStore } from "pinia";
31
+ import { ref, watch } from "vue";
32
+ var useNoydbI18n = defineStore("noydb-i18n", () => {
33
+ const locale = ref("en");
34
+ const fallback = ref(["en", "any"]);
35
+ function setLocale(l, opts) {
36
+ locale.value = l;
37
+ const sync = opts?.syncVault;
38
+ if (sync) {
39
+ const vaults = Array.isArray(sync) ? sync : [sync];
40
+ for (const v of vaults) v.setLocale(l);
41
+ }
42
+ }
43
+ function setFallback(chain) {
44
+ fallback.value = chain;
45
+ }
46
+ function bindTo(source, opts) {
47
+ return watch(
48
+ source,
49
+ (v) => {
50
+ locale.value = v;
51
+ },
52
+ // sync flush so the mirror propagates immediately (no tick lag) —
53
+ // a locale change should be observable synchronously by dependents.
54
+ { immediate: opts?.immediate ?? true, flush: "sync" }
55
+ );
56
+ }
57
+ return { locale, fallback, setLocale, setFallback, bindTo };
58
+ });
59
+
27
60
  // src/defineNoydbStore.ts
28
61
  function defineNoydbStore(id, options) {
29
62
  const collectionName = options.collection ?? id;
30
63
  const prefetch = options.prefetch ?? true;
31
- return defineStore(id, () => {
64
+ return defineStore2(id, () => {
32
65
  const items = shallowRef([]);
33
66
  const count = computed(() => items.value.length);
67
+ const i18nMode = options.i18n ?? "raw";
68
+ const i18nStore = i18nMode === "follow" ? useNoydbI18n() : null;
69
+ function localeOpts() {
70
+ if (i18nMode === "raw") return { locale: "raw" };
71
+ if (i18nMode === "follow") {
72
+ return { locale: i18nStore.locale, fallback: i18nStore.fallback };
73
+ }
74
+ const l = i18nMode.locale;
75
+ return {
76
+ locale: typeof l === "string" ? l : l.value,
77
+ ...i18nMode.fallback !== void 0 ? { fallback: i18nMode.fallback } : {}
78
+ };
79
+ }
80
+ const resolveVaultName = () => typeof options.vault === "function" ? options.vault() : options.vault;
34
81
  let cachedCompartment = null;
35
82
  let cachedCollection = null;
83
+ let boundVaultName = null;
36
84
  async function getCollection() {
37
- if (cachedCollection) return cachedCollection;
85
+ const vaultName = resolveVaultName();
86
+ if (cachedCollection && boundVaultName === vaultName) return cachedCollection;
38
87
  const noydb = resolveNoydb(options.noydb ?? null);
39
- cachedCompartment = await noydb.openVault(options.vault);
88
+ cachedCompartment = await noydb.openVault(vaultName);
40
89
  const collOpts = {};
41
90
  if (options.schema !== void 0) collOpts.schema = options.schema;
42
91
  if (options.attestation !== void 0) collOpts.attestation = options.attestation;
92
+ if (options.persistJsonSchema !== void 0) collOpts.persistJsonSchema = options.persistJsonSchema;
93
+ if (options.schemaUpdate !== void 0) collOpts.schemaUpdate = options.schemaUpdate;
94
+ if (options.i18nFields !== void 0) collOpts.i18nFields = options.i18nFields;
95
+ if (options.dictKeyFields !== void 0) collOpts.dictKeyFields = options.dictKeyFields;
43
96
  cachedCollection = cachedCompartment.collection(collectionName, collOpts);
97
+ boundVaultName = vaultName;
44
98
  return cachedCollection;
45
99
  }
46
100
  async function refresh() {
47
101
  const c = await getCollection();
48
- const list = await c.list();
102
+ const list = await c.list(localeOpts());
49
103
  items.value = list;
50
104
  }
51
105
  function byId(id2) {
@@ -57,7 +111,7 @@ function defineNoydbStore(id, options) {
57
111
  async function add(id2, record) {
58
112
  const c = await getCollection();
59
113
  await c.put(id2, record);
60
- items.value = await c.list();
114
+ items.value = await c.list(localeOpts());
61
115
  }
62
116
  async function update(id2, record) {
63
117
  await add(id2, record);
@@ -65,7 +119,7 @@ function defineNoydbStore(id, options) {
65
119
  async function remove(id2) {
66
120
  const c = await getCollection();
67
121
  await c.delete(id2);
68
- items.value = await c.list();
122
+ items.value = await c.list(localeOpts());
69
123
  }
70
124
  function query() {
71
125
  if (!cachedCollection) {
@@ -84,7 +138,7 @@ function defineNoydbStore(id, options) {
84
138
  const built = build(cachedCollection.query());
85
139
  const live = built.live();
86
140
  const items2 = shallowRef(live.value);
87
- const error = ref(live.error);
141
+ const error = ref2(live.error);
88
142
  const unsubscribe = live.subscribe(() => {
89
143
  items2.value = live.value;
90
144
  error.value = live.error;
@@ -100,6 +154,23 @@ function defineNoydbStore(id, options) {
100
154
  return { items: items2, error, stop };
101
155
  }
102
156
  const $ready = prefetch ? refresh() : Promise.resolve();
157
+ if (i18nMode === "follow") {
158
+ watch2(
159
+ () => [i18nStore.locale, i18nStore.fallback],
160
+ () => {
161
+ void refresh();
162
+ }
163
+ );
164
+ } else if (typeof i18nMode === "object" && isRef(i18nMode.locale)) {
165
+ watch2(i18nMode.locale, () => {
166
+ void refresh();
167
+ });
168
+ }
169
+ if (typeof options.vault === "function") {
170
+ watch2(resolveVaultName, (next, prev) => {
171
+ if (next !== prev) void refresh();
172
+ });
173
+ }
103
174
  return {
104
175
  items,
105
176
  count,
@@ -115,6 +186,102 @@ function defineNoydbStore(id, options) {
115
186
  });
116
187
  }
117
188
 
189
+ // src/useI18nField.ts
190
+ import { computed as computed2, unref } from "vue";
191
+ import { resolveI18nText } from "@noy-db/hub/i18n";
192
+ function useI18nField(source, opts = {}) {
193
+ const i18n = useNoydbI18n();
194
+ return computed2(() => {
195
+ const map = typeof source === "function" ? source() : source;
196
+ if (!map || typeof map !== "object") return null;
197
+ const locale = opts.locale !== void 0 ? unref(opts.locale) : i18n.locale;
198
+ const fallback = opts.fallback ?? i18n.fallback;
199
+ const out = resolveI18nText(
200
+ map,
201
+ locale,
202
+ fallback,
203
+ void 0,
204
+ { policy: "null" }
205
+ );
206
+ return typeof out === "string" ? out : null;
207
+ });
208
+ }
209
+
210
+ // src/useDictLabel.ts
211
+ import { ref as ref3, shallowRef as shallowRef2, toRef, watch as watch3 } from "vue";
212
+ function useDictLabel(dictionaryName, options = {}) {
213
+ const vault = resolveVault(options.vault);
214
+ const handle = vault.dictionary(dictionaryName);
215
+ let storeLocale = null;
216
+ let storeFallback = null;
217
+ if (options.locale === void 0 || options.fallback === void 0) {
218
+ try {
219
+ const i18n = useNoydbI18n();
220
+ storeLocale = toRef(i18n, "locale");
221
+ storeFallback = i18n.fallback;
222
+ } catch {
223
+ }
224
+ }
225
+ const localeRef = options.locale !== void 0 ? normaliseLocale(options.locale) : storeLocale ?? ref3("en");
226
+ const fallback = options.fallback ?? storeFallback ?? ["en", "any"];
227
+ const onMissingMode = options.onMissing ?? "key";
228
+ const missing = (key) => onMissingMode === "empty" ? "" : onMissingMode === "placeholder" ? `\u27E8missing:${key}\u27E9` : key;
229
+ const cache = /* @__PURE__ */ new Map();
230
+ const db = resolveNoydb();
231
+ const dictCollection = `_dict_${dictionaryName}`;
232
+ const onChange = (event) => {
233
+ if (event.collection !== dictCollection) return;
234
+ for (const [key, r] of cache) {
235
+ void refresh(key, r);
236
+ }
237
+ };
238
+ db.on("change", onChange);
239
+ watch3(localeRef, () => {
240
+ for (const [key, r] of cache) {
241
+ void refresh(key, r);
242
+ }
243
+ });
244
+ async function refresh(key, r) {
245
+ try {
246
+ const resolved = await handle.resolveLabel(
247
+ key,
248
+ localeRef.value,
249
+ fallback
250
+ );
251
+ r.value = resolved ?? missing(key);
252
+ } catch {
253
+ r.value = missing(key);
254
+ }
255
+ }
256
+ return (key) => {
257
+ let r = cache.get(key);
258
+ if (r) return r;
259
+ r = shallowRef2(missing(key));
260
+ cache.set(key, r);
261
+ void refresh(key, r);
262
+ return r;
263
+ };
264
+ }
265
+ function resolveVault(source) {
266
+ const db = resolveNoydb();
267
+ if (source && typeof source !== "string") return source;
268
+ if (typeof source === "string") {
269
+ return db.vault(source);
270
+ }
271
+ const anyDb = db;
272
+ if (anyDb.vaultCache && anyDb.vaultCache.size > 0) {
273
+ return [...anyDb.vaultCache.values()][0];
274
+ }
275
+ throw new Error(
276
+ '[@noy-db/in-pinia] useDictLabel: no open vault. Pass `{ vault: "name" }` or `await db.openVault(name)` first.'
277
+ );
278
+ }
279
+ function normaliseLocale(locale) {
280
+ if (locale === void 0) return ref3("en");
281
+ if (typeof locale === "string") return ref3(locale);
282
+ return locale;
283
+ }
284
+
118
285
  // src/plugin.ts
119
286
  import { createNoydb } from "@noy-db/hub";
120
287
  var STATE_DOC_ID = "__state__";
@@ -209,24 +376,24 @@ function pickKeys(state, persist) {
209
376
 
210
377
  // src/useCapabilityGrant.ts
211
378
  import {
212
- computed as computed2,
379
+ computed as computed3,
213
380
  getCurrentScope as getCurrentScope2,
214
381
  onScopeDispose as onScopeDispose2,
215
- ref as ref2,
216
- shallowRef as shallowRef2,
217
- watch
382
+ ref as ref4,
383
+ shallowRef as shallowRef3,
384
+ watch as watch4
218
385
  } from "vue";
219
386
  var CAPABILITY_REQUESTS_COLLECTION = "_capability_requests";
220
387
  function useCapabilityGrant(capability, options) {
221
- const state = ref2("idle");
222
- const error = ref2(null);
223
- const recordRef = shallowRef2(null);
388
+ const state = ref4("idle");
389
+ const error = ref4(null);
390
+ const recordRef = shallowRef3(null);
224
391
  const inBrowser = typeof window !== "undefined";
225
392
  let expiryTimer = null;
226
393
  let unsubscribeChangeStream = null;
227
394
  let resolvedVault = null;
228
395
  let stopped = false;
229
- async function resolveVault() {
396
+ async function resolveVault2() {
230
397
  if (resolvedVault) return resolvedVault;
231
398
  if (typeof options.vault === "string") {
232
399
  const noydb = resolveNoydb(null);
@@ -273,21 +440,21 @@ function useCapabilityGrant(capability, options) {
273
440
  state.value = "idle";
274
441
  recordRef.value = null;
275
442
  }
276
- const now = ref2(Date.now());
443
+ const now = ref4(Date.now());
277
444
  const tickTimer = inBrowser ? setInterval(() => {
278
445
  now.value = Date.now();
279
446
  }, 1e3) : null;
280
- const timeRemaining = computed2(() => {
447
+ const timeRemaining = computed3(() => {
281
448
  if (state.value !== "granted" || !recordRef.value?.expiresAt) return 0;
282
449
  void now.value;
283
450
  const ms = new Date(recordRef.value.expiresAt).getTime() - Date.now();
284
451
  return ms > 0 ? ms : 0;
285
452
  });
286
- watch(
453
+ watch4(
287
454
  () => recordRef.value?.id,
288
455
  async (id) => {
289
456
  if (!inBrowser || !id || unsubscribeChangeStream) return;
290
- const vault = await resolveVault();
457
+ const vault = await resolveVault2();
291
458
  const coll = vault.collection(
292
459
  CAPABILITY_REQUESTS_COLLECTION
293
460
  );
@@ -319,7 +486,7 @@ function useCapabilityGrant(capability, options) {
319
486
  error.value = null;
320
487
  if (!inBrowser) return;
321
488
  try {
322
- const vault = await resolveVault();
489
+ const vault = await resolveVault2();
323
490
  const coll = vault.collection(
324
491
  CAPABILITY_REQUESTS_COLLECTION
325
492
  );
@@ -352,7 +519,7 @@ function useCapabilityGrant(capability, options) {
352
519
  }
353
520
  error.value = null;
354
521
  try {
355
- const vault = await resolveVault();
522
+ const vault = await resolveVault2();
356
523
  if (vault.role !== options.approver && vault.role !== "owner") {
357
524
  throw new Error(
358
525
  `useCapabilityGrant: caller role "${vault.role}" cannot approve a "${options.approver}"-tier grant`
@@ -388,7 +555,7 @@ function useCapabilityGrant(capability, options) {
388
555
  error.value = null;
389
556
  try {
390
557
  clearExpiryTimer();
391
- const vault = await resolveVault();
558
+ const vault = await resolveVault2();
392
559
  const released = { ...record, status: "released" };
393
560
  const coll = vault.collection(
394
561
  CAPABILITY_REQUESTS_COLLECTION
@@ -419,6 +586,9 @@ export {
419
586
  getActiveNoydb,
420
587
  resolveNoydb,
421
588
  setActiveNoydb,
422
- useCapabilityGrant
589
+ useCapabilityGrant,
590
+ useDictLabel,
591
+ useI18nField,
592
+ useNoydbI18n
423
593
  };
424
594
  //# sourceMappingURL=index.js.map