mnfst 0.5.256 → 0.5.258

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.256';
5
+ const MANIFEST_BUILD_VERSION = '0.5.258';
6
6
 
7
7
  /* Manifest Data Sources - Appwrite Integration */
8
8
 
@@ -298,8 +298,7 @@ if (!window.ManifestRealtimeHub) {
298
298
  status: 'online',
299
299
  metadata: null,
300
300
  scope: 'auto', // 'auto'/'team' = current team, 'global', or an explicit team id
301
- teamsEnabled: false, // manifest.appwrite.auth.teams (read at start)
302
- settleTimer: null, // bounded wait for teams to settle
301
+ teamsEnabled: false, // manifest.appwrite.auth.teams (read in ensureServices)
303
302
  auto: true, // focus/blur auto-flip
304
303
  heartbeatMs: 25000, // TTL refresh cadence
305
304
  onFocus: null,
@@ -363,6 +362,12 @@ if (!window.ManifestRealtimeHub) {
363
362
  if (!A || !A.Presences || !A.Realtime || !window.ManifestRealtimeHub) return false;
364
363
  const services = await window.ManifestAppwriteAuthConfig?.getAppwriteClient?.();
365
364
  if (!services?.client) return false;
365
+ // teamsEnabled gates the scoped (never-users()) grant: resolve it here
366
+ // so pre-start set() writes are covered, not only start()
367
+ try {
368
+ const authCfg = await window.ManifestAppwriteAuthConfig?.getAppwriteConfig?.();
369
+ ctx.teamsEnabled = !!authCfg?.teams;
370
+ } catch (e) { ctx.teamsEnabled = false; }
366
371
  ctx.client = services.client;
367
372
  ctx.presences = new A.Presences(services.client);
368
373
  return true;
@@ -370,23 +375,6 @@ if (!window.ManifestRealtimeHub) {
370
375
 
371
376
  /* Scope */
372
377
 
373
- // Teams load in the background after auth init; until they settle, a scoped
374
- // write must not fall back to read(users()) — that is the cross-tenant
375
- // broadcast window. Settles on the auth event, or after a bounded wait for
376
- // sessions the background load never covers (e.g. guests without guestTeams).
377
- let teamsSettled = false;
378
- window.addEventListener('manifest:auth:teams-loaded', () => { settleTeams(); });
379
- ['manifest:auth:logout', 'manifest:auth:session-cleared', 'manifest:auth:login', 'manifest:auth:anonymous'].forEach(type =>
380
- window.addEventListener(type, () => { teamsSettled = false; }));
381
- function settleTeams() {
382
- if (teamsSettled) return;
383
- teamsSettled = true;
384
- if (ctx.settleTimer) { clearTimeout(ctx.settleTimer); ctx.settleTimer = null; }
385
- // Settled with a team: the team-switch effect rescopes. Settled with
386
- // none: rewrite here, from self-only to the global users() grant.
387
- if (ctx.started && !scopeTeamId()) { hydrate(); rescope(); }
388
- }
389
-
390
378
  // Roster scope as a team id: explicit id > current team ('auto'/'team') > none ('global')
391
379
  function scopeTeamId() {
392
380
  const s = ctx.scope;
@@ -491,13 +479,13 @@ if (!window.ManifestRealtimeHub) {
491
479
  ctx.metadata = metadata !== undefined ? metadata : ctx.metadata;
492
480
 
493
481
  // Read-scope + owner write (owner update/delete required, else updates 401).
494
- // Reads follow the roster scope: team role when scoped, all users when
495
- // global. Scoped with teams NOT yet settled: self-only — never the
496
- // users() broadcast (the leak window); settle/team-switch rewrites it.
482
+ // Scoped (teams enabled, scope not global): team grant when resolved,
483
+ // self-only until then — however long teams take — never the users()
484
+ // broadcast. users() is only for global scope or teams-disabled projects.
485
+ // The team-switch effect rescopes reactively when a team resolves/changes.
497
486
  const teamId = scopeTeamId();
498
- const pending = !teamId && ctx.teamsEnabled && !teamsSettled
499
- && ctx.scope !== 'global' && ctx.scope !== false;
500
- const readRole = teamId ? A.Role.team(teamId) : (pending ? A.Role.user(user.$id) : A.Role.users());
487
+ const scoped = ctx.teamsEnabled && ctx.scope !== 'global' && ctx.scope !== false && ctx.scope != null;
488
+ const readRole = teamId ? A.Role.team(teamId) : (scoped ? A.Role.user(user.$id) : A.Role.users());
501
489
  const permissions = [
502
490
  A.Permission.read(readRole),
503
491
  A.Permission.update(A.Role.user(user.$id)),
@@ -566,18 +554,6 @@ if (!window.ManifestRealtimeHub) {
566
554
  if (!(await ensureServices())) { if (s) s.error = 'Appwrite Presences unavailable'; return false; }
567
555
  if (ctx.started) return true;
568
556
 
569
- // Teams settle via the auth plugin's background load; disabled teams or
570
- // an already-active team settle now, and a bounded wait covers sessions
571
- // the load never fires for (e.g. guests without guestTeams)
572
- try {
573
- const authCfg = await window.ManifestAppwriteAuthConfig?.getAppwriteConfig?.();
574
- ctx.teamsEnabled = !!authCfg?.teams;
575
- } catch (e) { ctx.teamsEnabled = false; }
576
- if (!ctx.teamsEnabled || currentTeamId()) settleTeams();
577
- else if (!teamsSettled && !ctx.settleTimer) {
578
- ctx.settleTimer = setTimeout(() => { ctx.settleTimer = null; settleTeams(); }, 8000);
579
- }
580
-
581
557
  ctx.started = true;
582
558
 
583
559
  await hydrate();
@@ -600,7 +576,6 @@ if (!window.ManifestRealtimeHub) {
600
576
  }
601
577
 
602
578
  function stop() {
603
- if (ctx.settleTimer) { clearTimeout(ctx.settleTimer); ctx.settleTimer = null; }
604
579
  if (ctx.heartbeat) { clearInterval(ctx.heartbeat); ctx.heartbeat = null; }
605
580
  if (ctx.onBlur) { window.removeEventListener('blur', ctx.onBlur); ctx.onBlur = null; }
606
581
  if (ctx.onFocus) { window.removeEventListener('focus', ctx.onFocus); ctx.onFocus = null; }
package/lib/manifest.d.ts CHANGED
@@ -306,7 +306,7 @@ export interface ManifestPush {
306
306
  [extra: string]: unknown;
307
307
  }
308
308
 
309
- /** `$secure` from the device plugin — secure key-value storage (native keychain or fallback). */
309
+ /** `$secure` from the device plugin — Keychain/Keystore via a native plugin; unencrypted localStorage on the web only; rejects on native without a plugin. */
310
310
  export interface ManifestSecure {
311
311
  get(key: string): Promise<string | null>;
312
312
  set(key: string, value: string): Promise<void>;
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.256';
5
+ const MANIFEST_BUILD_VERSION = '0.5.258';
6
6
 
7
7
  /* Manifest Data Sources - Configuration */
8
8
 
@@ -251,11 +251,12 @@ function manifestSecureMissingBackend(msg) {
251
251
  return { get: fail('get'), set: fail('set'), remove: fail('remove'), keys: fail('keys'), clear: fail('clear') };
252
252
  }
253
253
 
254
- // Missing backends aren't cached, so a later-registered plugin is picked up
254
+ // Native and use() backends cached; web reused but never chosen on native
255
255
  let _manifestSecureBackend = null;
256
+ let _manifestSecureWeb = null;
256
257
  function manifestSecureBackend() {
257
258
  if (_manifestSecureBackend) return _manifestSecureBackend;
258
- if (!manifestNativeIsNative()) return (_manifestSecureBackend = manifestSecureWebBackend());
259
+ if (!manifestNativeIsNative()) return _manifestSecureWeb || (_manifestSecureWeb = manifestSecureWebBackend());
259
260
  const plugin = manifestNativePlugin('SecureStorage');
260
261
  if (!plugin) return manifestSecureMissingBackend(MANIFEST_SECURE_NONE);
261
262
  if (!manifestNativeInstalled('SecureStorage')) return manifestSecureMissingBackend(MANIFEST_SECURE_UNSYNCED);
@@ -480,7 +481,7 @@ function manifestBiometricPlugin() {
480
481
  if (Array.isArray(headers)) {
481
482
  for (const name of MANIFEST_BIOMETRIC_PLUGINS) {
482
483
  const plugin = manifestNativePlugin(name);
483
- if (plugin && headers.some(h => h && h.name === name)) return { name, plugin };
484
+ if (plugin && manifestNativeInstalled(name)) return { name, plugin };
484
485
  }
485
486
  manifestBiometricWarnNotNative();
486
487
  return null;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest.appwrite.auth.js": "sha384-9WNhIeSEzxxJm+yP7cV41kV2xyzyXgFCNpThqiREcNbb6tnIW6O7VRZPL2jwy9Nk",
3
- "manifest.appwrite.data.js": "sha384-ot7BHrPKWwiWjT10bvg7/hVKHADiMVTG0zoC0zlG389de40O/L7YFzd3ZzDnKXN5",
4
- "manifest.appwrite.presences.js": "sha384-qsRtzFCtW7pS+I95EQuZQoPAeZvBsNDSMFwDFBJriyCWcNv2Jo2KFvOweClJhowJ",
3
+ "manifest.appwrite.data.js": "sha384-zpWExEiCs/Ccl9jDr2MSU5BU9MD0G69HFxsAg4el4T+slUj5a/dJa4WZuUmU3XkX",
4
+ "manifest.appwrite.presences.js": "sha384-/CagPsgWhO1sWEevCNGJmZ/ezRK9YCjLjvF7hxNSM4gVlJmEVtfSLfF7wnsRq441",
5
5
  "manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
6
6
  "manifest.charts.js": "sha384-G+huD7UvjF9zDovdVVlh4I5X1Mq4oNnJfoFg4NnGdP3R/4Skq9hy5cGuHNYLxDYm",
7
7
  "manifest.chat.js": "sha384-88DfMfJLoi2oxclVD2iIMDkIGAExMXq5k47mekUredlicLaP3oZY5bwtwqs+TqDF",
@@ -11,24 +11,24 @@
11
11
  "manifest.combobox.js": "sha384-MILTkrgsTzsYUjGo4ZuADqV85Xs4GmfB4xexfe9vbJMIoQTZ42W4zs+DTaVSPEsx",
12
12
  "manifest.components.js": "sha384-BUFA8h+G5Plr82sV7bKzO42pPoiRZwRQcKj1lt2ROFiKjjlkayU/vmkAFqEsdBA+",
13
13
  "manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
14
- "manifest.data.js": "sha384-1BIeRvJ8LOJLtCX4uPCepikXSOaSisgTTwfdRYAbChowEGJX1WGC7cfSSBsld0sM",
14
+ "manifest.data.js": "sha384-xGbKjNmwqUapD++Kjx1XA/IAl01e1WiOVnXB/8XqX5mDgsyythAq1joIGY13XpYO",
15
15
  "manifest.datepicker.js": "sha384-2XwFFnS4Bg5FDvG/v8x6KUvrjcBQEOYyTxynX2K/D/Qb3PI6+Y04lEwCnVDJLzwL",
16
16
  "manifest.defer.js": "sha384-GK9qJkYtchtyzSQ+3zmDQUJE3+au4qthT2M8JnFjXxgfwCH5IVKc2r3tackgMryU",
17
- "manifest.device.js": "sha384-AWismZl/UjR/NqH7z4Sfg0DZLPpySDuS0tL34ZsbHdNYDD14JzBW9xp/ScmQKilQ",
17
+ "manifest.device.js": "sha384-YeQaS56L8IILqrQNBSeAOLwIh5DuAOrE60cYLK1+46qJtUrXlAvqGe2j5mbV4Vq7",
18
18
  "manifest.dropdowns.js": "sha384-acufUps7R9WjqB4XXW5JLACqniuHJGM4CNTb2rF4B2Q/jv7ZRmsAwfr2McanOz3s",
19
19
  "manifest.edit.js": "sha384-MOgQNdNLeHijhR0u2W6ntoOulKFglsATCFDqkinesOU15tHoILk/JNzHKkGi5dUG",
20
20
  "manifest.export.js": "sha384-Rx6XvqBZc4apzP/FwcDr6yIln4/zNa08Q4ZqBZcEqUz1aNZQfl4h0+Ae7mqCQyuG",
21
21
  "manifest.icons.js": "sha384-kKOINpX70YzNO3FvkV6umrmO3f0KIu0DNbwB+ej55a7y/lhU7v/myQtXL0bwCTbt",
22
22
  "manifest.localization.js": "sha384-EImsIw8Z3l13V5eH9ZJF/yfsOfIvR1oPRNSArANkPji7V8O3IRf6zMwsNiAGj3Hk",
23
23
  "manifest.markdown.js": "sha384-heyDR40LXHaAmAuA+fa381uFwShk1oAqpFFY6E2Qq4T3VN0TQfRqyc++MF40K5Hj",
24
- "manifest.native.js": "sha384-AWismZl/UjR/NqH7z4Sfg0DZLPpySDuS0tL34ZsbHdNYDD14JzBW9xp/ScmQKilQ",
24
+ "manifest.native.js": "sha384-YeQaS56L8IILqrQNBSeAOLwIh5DuAOrE60cYLK1+46qJtUrXlAvqGe2j5mbV4Vq7",
25
25
  "manifest.payments.js": "sha384-8pofk2zhxtapPMpwnFyTelPMrYhShNhDCE722uQh/EYFvZFuPLmSdgunqsarVQjv",
26
26
  "manifest.rich.text.js": "sha384-ZBV9jXmu2nmprEHicddRE/m7nR4RPZtVc969Jte0+EJYBcVph7itkjcgN/61PyeC",
27
27
  "manifest.router.js": "sha384-9LMIkwrgnxmmFDv70TND2MRJF1z6Nl4yqG7fH5DbJ8oUIhdu/u4yUPSime1/EYhP",
28
28
  "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
29
29
  "manifest.status.js": "sha384-MBO345ab7H6Uq1X2dZLt4Ge1Gcra+Z2qYApvlAeIV8CJhDDJrz2FPXpp+Kcp8zcM",
30
30
  "manifest.svg.js": "sha384-qr/8H9+2cIhSXNbRWRtIdrDlTOxKlNJqwEefHvCYoiBNW/kKhPTFa109Orv/EBnb",
31
- "manifest.sw.js": "sha384-BQY7u/VfJ7DZ23QutEXo4OU+EO646rWLdHPTLRB3JzwIY5InbZEtxAPYKMlQGu35",
31
+ "manifest.sw.js": "sha384-8xS3BLZdBXUL7CSmurvYh6v1bvI1+X56IXme2ng3lTYzwLjLHdOYQEkll4YFpKj1",
32
32
  "manifest.tabs.js": "sha384-otU09H7jnawVKQdLAYpMCd3jx00tgyPVr42D2hLIBzN5dG4se505YesavdnMqEi1",
33
33
  "manifest.tailwind.js": "sha384-r/Jvqb+Piz21jUts10BbVAJoKkShOdJRVFpywyi4HPIi/OfOJq5CtPyWAPbdkMgt",
34
34
  "manifest.toasts.js": "sha384-3zkWxzw693pxg3QDFsoYCA3CqYaLKmBaMArULXODD66Utolpewl0OAeTB92aWUVv",
@@ -251,11 +251,12 @@ function manifestSecureMissingBackend(msg) {
251
251
  return { get: fail('get'), set: fail('set'), remove: fail('remove'), keys: fail('keys'), clear: fail('clear') };
252
252
  }
253
253
 
254
- // Missing backends aren't cached, so a later-registered plugin is picked up
254
+ // Native and use() backends cached; web reused but never chosen on native
255
255
  let _manifestSecureBackend = null;
256
+ let _manifestSecureWeb = null;
256
257
  function manifestSecureBackend() {
257
258
  if (_manifestSecureBackend) return _manifestSecureBackend;
258
- if (!manifestNativeIsNative()) return (_manifestSecureBackend = manifestSecureWebBackend());
259
+ if (!manifestNativeIsNative()) return _manifestSecureWeb || (_manifestSecureWeb = manifestSecureWebBackend());
259
260
  const plugin = manifestNativePlugin('SecureStorage');
260
261
  if (!plugin) return manifestSecureMissingBackend(MANIFEST_SECURE_NONE);
261
262
  if (!manifestNativeInstalled('SecureStorage')) return manifestSecureMissingBackend(MANIFEST_SECURE_UNSYNCED);
@@ -480,7 +481,7 @@ function manifestBiometricPlugin() {
480
481
  if (Array.isArray(headers)) {
481
482
  for (const name of MANIFEST_BIOMETRIC_PLUGINS) {
482
483
  const plugin = manifestNativePlugin(name);
483
- if (plugin && headers.some(h => h && h.name === name)) return { name, plugin };
484
+ if (plugin && manifestNativeInstalled(name)) return { name, plugin };
484
485
  }
485
486
  manifestBiometricWarnNotNative();
486
487
  return null;
@@ -413,6 +413,23 @@
413
413
  }
414
414
  ]
415
415
  },
416
+ "presence": {
417
+ "description": "Alias of presences — enable the $presence plugin: true, or an options object.",
418
+ "oneOf": [
419
+ {
420
+ "type": "boolean"
421
+ },
422
+ {
423
+ "type": "object",
424
+ "properties": {
425
+ "scope": {
426
+ "type": "string",
427
+ "description": "Roster scope: 'auto'/'team' (current team when one is active, default), 'global', or an explicit team id. May reference an env var via ${VAR_NAME}."
428
+ }
429
+ }
430
+ }
431
+ ]
432
+ },
416
433
  "auth": {
417
434
  "type": "object",
418
435
  "properties": {
@@ -16,7 +16,7 @@
16
16
 
17
17
  // Build stamps the published version here; unstamped (dev) falls back to the
18
18
  // registration URL's `v`, then 'dev'.
19
- const BUILD_VERSION = '0.5.256';
19
+ const BUILD_VERSION = '0.5.258';
20
20
  const CACHE_PREFIX = 'mnfst-sw:';
21
21
  const META_CACHE = CACHE_PREFIX + 'meta';
22
22
  // Sized to hold a full precache.json warm-up (PRECACHE_MAX_ENTRIES server-side)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.256",
3
+ "version": "0.5.258",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",