mnfst 0.5.197 → 0.5.198-next.1
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/lib/manifest.appwrite.data.js +27 -23
- package/lib/manifest.combobox.js +1 -0
- package/lib/manifest.computed.js +52 -0
- package/lib/manifest.d.ts +8 -1
- package/lib/manifest.data.js +513 -784
- package/lib/manifest.datepicker.js +2 -0
- package/lib/manifest.defer.js +271 -0
- package/lib/manifest.dropdowns.js +19 -4
- package/lib/manifest.integrity.json +8 -6
- package/lib/manifest.js +2 -0
- package/package.json +4 -2
|
@@ -104,6 +104,32 @@ async function getAppwriteDataServices() {
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// Auth pre-flight: one shared account.get() in flight; a pass is cached until auth state changes
|
|
108
|
+
let authCheck = null;
|
|
109
|
+
let authVerified = false;
|
|
110
|
+
['manifest:auth:login', 'manifest:auth:logout', 'manifest:auth:anonymous', 'manifest:auth:session-cleared', 'manifest:auth:initialized']
|
|
111
|
+
.forEach(type => window.addEventListener(type, () => { authCheck = null; authVerified = false; }));
|
|
112
|
+
|
|
113
|
+
async function verifyAuthenticated() {
|
|
114
|
+
if (!window.ManifestAppwriteAuthConfig || authVerified) return;
|
|
115
|
+
if (!authCheck) {
|
|
116
|
+
authCheck = (async () => {
|
|
117
|
+
const { client } = await window.ManifestAppwriteAuthConfig.getAppwriteClient();
|
|
118
|
+
if (!client || !window.Appwrite?.Account) return true;
|
|
119
|
+
try {
|
|
120
|
+
await new window.Appwrite.Account(client).get();
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error?.code === 401) return false;
|
|
123
|
+
}
|
|
124
|
+
authVerified = true; // Anonymous / API-key access proceeds too
|
|
125
|
+
return true;
|
|
126
|
+
})().catch(() => true).finally(() => { authCheck = null; });
|
|
127
|
+
}
|
|
128
|
+
if (!(await authCheck)) {
|
|
129
|
+
throw new Error('[Manifest Data] User not authenticated. Please sign in to Appwrite first.');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
107
133
|
// Load rows from Appwrite table
|
|
108
134
|
async function loadTableRows(databaseId, tableId, queries = []) {
|
|
109
135
|
const services = await getAppwriteDataServices();
|
|
@@ -111,29 +137,7 @@ async function loadTableRows(databaseId, tableId, queries = []) {
|
|
|
111
137
|
throw new Error('[Manifest Data] Appwrite TablesDB service not available');
|
|
112
138
|
}
|
|
113
139
|
|
|
114
|
-
|
|
115
|
-
// Skip if using API key or anonymous access
|
|
116
|
-
if (window.ManifestAppwriteAuthConfig) {
|
|
117
|
-
try {
|
|
118
|
-
const { client } = await window.ManifestAppwriteAuthConfig.getAppwriteClient();
|
|
119
|
-
if (client && window.Appwrite?.Account) {
|
|
120
|
-
const account = new window.Appwrite.Account(client);
|
|
121
|
-
try {
|
|
122
|
-
await account.get(); // This will throw if not authenticated
|
|
123
|
-
} catch (authError) {
|
|
124
|
-
// Only throw if auth plugin is being used - otherwise allow anonymous/API key access
|
|
125
|
-
if (authError.code === 401) {
|
|
126
|
-
throw new Error('[Manifest Data] User not authenticated. Please sign in to Appwrite first.');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
} catch (authCheckError) {
|
|
131
|
-
// If auth check fails, still try the request (might be anonymous access or API key)
|
|
132
|
-
if (authCheckError.message?.includes('not authenticated')) {
|
|
133
|
-
throw authCheckError;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
140
|
+
await verifyAuthenticated();
|
|
137
141
|
|
|
138
142
|
try {
|
|
139
143
|
const response = await services.tablesDB.listRows({
|
package/lib/manifest.combobox.js
CHANGED
|
@@ -410,6 +410,7 @@ function initializeComboboxPlugin() {
|
|
|
410
410
|
generatedMenu = menu; // tracked so cleanup() can remove it on re-render
|
|
411
411
|
if (src) src.style.setProperty('display', 'none', 'important');
|
|
412
412
|
menu.setAttribute('popover', 'manual');
|
|
413
|
+
menu.setAttribute('x-defer.off', ''); // options are built here, not by directives
|
|
413
414
|
menu.id = 'combobox-menu-' + rand();
|
|
414
415
|
menu.setAttribute('role', 'listbox');
|
|
415
416
|
if (multiple) menu.setAttribute('aria-multiselectable', 'true');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* Manifest Computed */
|
|
2
|
+
|
|
3
|
+
(function () {
|
|
4
|
+
|
|
5
|
+
// $computed(fn): cached derivation — recomputed once per flush when a tracked dependency changes
|
|
6
|
+
function computed(fn) {
|
|
7
|
+
if (typeof fn !== 'function') throw new TypeError('[Manifest Computed] $computed expects a function');
|
|
8
|
+
return Alpine.interceptor(() => {}, obj => {
|
|
9
|
+
obj.initialize = (data, path, key) => install(data, key, fn);
|
|
10
|
+
})(fn);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function install(data, key, fn) {
|
|
14
|
+
let value;
|
|
15
|
+
let failed = false;
|
|
16
|
+
let first = true;
|
|
17
|
+
|
|
18
|
+
const compute = () => {
|
|
19
|
+
try {
|
|
20
|
+
value = fn.call(data);
|
|
21
|
+
failed = false;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
// Keep the last good value; report once per failure streak
|
|
24
|
+
if (!failed) console.warn(`[Manifest Computed] "${key}" threw — keeping its last value`, error);
|
|
25
|
+
failed = true;
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const effect = Alpine.effect(() => {
|
|
31
|
+
const next = compute();
|
|
32
|
+
if (first) { first = false; return; }
|
|
33
|
+
data[key] = next;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Release with the owning element (stores have no $el and live for the page)
|
|
37
|
+
const el = data.$el;
|
|
38
|
+
if (el) Alpine.onElRemoved(el, () => Alpine.release(effect));
|
|
39
|
+
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function initializeComputedPlugin() {
|
|
44
|
+
Alpine.magic('computed', () => computed);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
window.$computed = computed;
|
|
48
|
+
|
|
49
|
+
document.addEventListener('alpine:init', initializeComputedPlugin);
|
|
50
|
+
if (window.Alpine && typeof window.Alpine.magic === 'function') initializeComputedPlugin();
|
|
51
|
+
|
|
52
|
+
})();
|
package/lib/manifest.d.ts
CHANGED
|
@@ -412,7 +412,7 @@ export interface ManifestTextEdit {
|
|
|
412
412
|
export type ManifestDirective =
|
|
413
413
|
| 'x-route' | 'x-anchors'
|
|
414
414
|
| 'x-icon' | 'x-svg' | 'x-markdown' | 'x-code' | 'x-code-group'
|
|
415
|
-
| 'x-toast' | 'x-tooltip' | 'x-carousel' | 'x-virtual' | 'x-resize'
|
|
415
|
+
| 'x-toast' | 'x-tooltip' | 'x-carousel' | 'x-virtual' | 'x-resize' | 'x-defer'
|
|
416
416
|
| 'x-chart' | 'x-date' | 'x-color' | 'x-colorpicker' | 'x-combobox'
|
|
417
417
|
| 'x-export' | 'x-pay' | 'x-files' | 'x-data-files'
|
|
418
418
|
| 'x-edit' | 'x-text-edit';
|
|
@@ -430,6 +430,11 @@ declare global {
|
|
|
430
430
|
const $modify: ManifestModify;
|
|
431
431
|
/** Run a callback safely, returning undefined on error. */
|
|
432
432
|
const $try: ManifestTry;
|
|
433
|
+
/**
|
|
434
|
+
* Cached derivation for `x-data` / `Alpine.data` scopes: `rows: $computed(function () { return this.items.filter(…) })`.
|
|
435
|
+
* Recomputed once per flush when a tracked dependency changes; reads as a plain property with a stable identity in between.
|
|
436
|
+
*/
|
|
437
|
+
const $computed: <T>(fn: (this: any) => T) => T;
|
|
433
438
|
/** Appwrite auth plugin (present when the plugin is loaded). */
|
|
434
439
|
const $auth: ManifestAuth;
|
|
435
440
|
/** Localization plugin. */
|
|
@@ -485,6 +490,8 @@ declare global {
|
|
|
485
490
|
loadPlugin(name: string, version?: string): Promise<unknown>;
|
|
486
491
|
loadTailwind(version?: string): Promise<unknown>;
|
|
487
492
|
getPluginUrl(name: string, version?: string): string;
|
|
493
|
+
/** Defer a closed container built at runtime (call before Alpine.initTree). */
|
|
494
|
+
defer?(el: Element): unknown;
|
|
488
495
|
};
|
|
489
496
|
Alpine?: unknown;
|
|
490
497
|
__manifestLoaded?: unknown;
|