@feltdb/core 0.6.1 → 0.6.3
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/cli/commands.js +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +0 -4
- package/dist/studio-app/assets/{index-LQmvJSq6.js → index-BF45M757.js} +1 -1
- package/dist/studio-app/index.html +1 -1
- package/dist/telemetry.js +1 -1
- package/dist/workspace/workspace-connection.d.ts +8 -20
- package/dist/workspace/workspace-connection.d.ts.map +1 -1
- package/dist/workspace/workspace-connection.js +165 -39
- package/package.json +2 -1
package/dist/cli/commands.js
CHANGED
|
@@ -525,6 +525,7 @@ async function handleDev(args) {
|
|
|
525
525
|
if (workspace) {
|
|
526
526
|
const token = generatePairingToken();
|
|
527
527
|
token.workspaceId = workspace.workspaceId;
|
|
528
|
+
token.endpoint = process.env.VITE_FELTDB_URL;
|
|
528
529
|
persistPairingToken(process.cwd(), token);
|
|
529
530
|
pairingToken = token.token;
|
|
530
531
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import * as path from 'path';
|
|
|
23
23
|
import * as readline from 'readline';
|
|
24
24
|
import { getClient } from './api-client.js';
|
|
25
25
|
import { loadFeltDBConfig, createDefaultConfig, validateModel, } from './config.js';
|
|
26
|
-
const VERSION = '0.6.
|
|
26
|
+
const VERSION = '0.6.3';
|
|
27
27
|
function prompt(question) {
|
|
28
28
|
const rl = readline.createInterface({
|
|
29
29
|
input: process.stdin,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// One release train keeps generated applications installable. The repository
|
|
2
2
|
// validation script checks these values against every workspace manifest.
|
|
3
|
-
export const FELTDB_PACKAGE_VERSION = '0.6.
|
|
3
|
+
export const FELTDB_PACKAGE_VERSION = '0.6.3';
|
|
4
4
|
export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
|
|
@@ -5856,10 +5856,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
5856
5856
|
axum::routing::patch(platform_update_application_member),
|
|
5857
5857
|
)
|
|
5858
5858
|
.route("/api/tenants/{tenant_id}", get(get_tenant))
|
|
5859
|
-
.route(
|
|
5860
|
-
"/api/certification/fixtures/{application_id}",
|
|
5861
|
-
axum::routing::delete(delete_certification_fixture),
|
|
5862
|
-
)
|
|
5863
5859
|
.route("/api/keys", get(list_keys).post(create_key))
|
|
5864
5860
|
.route("/api/keys/{id}", axum::routing::delete(revoke_key))
|
|
5865
5861
|
.route(
|
|
@@ -25,4 +25,4 @@ Please change the parent <Route path="${e}"> to <Route path="${e===`/`?`*`:`${e}
|
|
|
25
25
|
`)}\n }`);for(let n of e.triggers)t.push(` trigger on ${n.event} {\n${n.statements.map(e=>` ${e}`).join(`
|
|
26
26
|
`)}\n }`);for(let n of e.policies)t.push(Hr(`policy`,n));for(let n of e.schedules)t.push(Hr(`schedule`,n));return`app ${e.app} {\n${t.join(`
|
|
27
27
|
|
|
28
|
-
`)}\n}\n`}function Wr(e,t){let n=e=>new Map([...e.collections.map(e=>[`collection ${e.name}`,JSON.stringify(e)]),...e.capabilities.map(e=>[`capability ${e.name}`,JSON.stringify(e)]),...e.agents.map(e=>[`agent ${e.name}`,JSON.stringify(e)]),...e.workflows.map(e=>[`workflow ${e.name}`,JSON.stringify(e)]),...e.triggers.map(e=>[`trigger ${e.event}`,JSON.stringify(e)]),...e.policies.map(e=>[`policy ${e.name}`,JSON.stringify(e)]),...e.schedules.map(e=>[`schedule ${e.name}`,JSON.stringify(e)])]),r=n(e),i=n(t);return{added:[...i.keys()].filter(e=>!r.has(e)),removed:[...r.keys()].filter(e=>!i.has(e)),changed:[...i.keys()].filter(e=>r.has(e)&&r.get(e)!==i.get(e))}}function Gr(e,t){let n=[],r=new Map(e.collections.map(e=>[e.name,e])),i=new Map(t.collections.map(e=>[e.name,e]));for(let[e,t]of i){let i=r.get(e);if(!i){n.push({kind:`add`,target:`collection ${e}`,safety:`safe`,detail:`Create collection model`});continue}let a=new Map(i.fields.map(e=>[e.name,e])),o=new Map(t.fields.map(e=>[e.name,e]));for(let[t,r]of o){let i=a.get(t);i?(i.type!==r.type||i.optional!==r.optional)&&n.push({kind:`change`,target:`${e}.${t}`,safety:`requires_transform`,detail:`${i.type}${i.optional?`?`:``} → ${r.type}${r.optional?`?`:``}`}):n.push({kind:`add`,target:`${e}.${t}`,safety:r.optional?`safe`:`requires_transform`,detail:r.optional?`Add optional field`:`Required field needs a backfill`})}for(let t of a.keys())o.has(t)||n.push({kind:`remove`,target:`${e}.${t}`,safety:`destructive`,detail:`Field is no longer declared`})}for(let e of r.keys())i.has(e)||n.push({kind:`remove`,target:`collection ${e}`,safety:`destructive`,detail:`Collection model is no longer declared`});let a=Wr(e,t);for(let e of a.added.filter(e=>!e.startsWith(`collection `)))n.push({kind:`add`,target:e,safety:`safe`,detail:`Deploy application primitive`});for(let e of a.changed.filter(e=>!e.startsWith(`collection `)))n.push({kind:`change`,target:e,safety:`safe`,detail:`Version application primitive`});for(let e of a.removed.filter(e=>!e.startsWith(`collection `)))n.push({kind:`remove`,target:e,safety:`destructive`,detail:`Application primitive is no longer declared`});return n}function Kr(e=`MyApp`){return{version:1,app:e,collections:[],capabilities:[],agents:[],workflows:[],triggers:[],policies:[],schedules:[]}}var qr=class{constructor(e=`offline`){this.value=e,this.listeners=new Set}subscribe(e){return this.listeners.add(e),e(this.value),()=>this.listeners.delete(e)}set(e){this.value=e;for(let t of this.listeners)t(e)}get(){return this.value}},Jr=class{constructor(e){this.config=e,this.status=new qr,this.fetcher=e.fetcher||fetch,this.restore()}key(){return`feltdb:sync:v1:${this.config.device.application_id}:${this.config.device.device_id}`}restore(){if(!(typeof localStorage>`u`))try{let e=JSON.parse(localStorage.getItem(this.key())||`{}`);this.sessionId=e.sessionId,this.cursor=e.cursor,this.error=e.error}catch{}}persist(){typeof localStorage<`u`&&localStorage.setItem(this.key(),JSON.stringify({sessionId:this.sessionId,cursor:this.cursor,error:this.error,outbox:this.readOutbox()}))}readOutbox(){if(typeof localStorage>`u`)return[];try{return JSON.parse(localStorage.getItem(`${this.key()}:outbox`)||`[]`)}catch{return[]}}writeOutbox(e){typeof localStorage<`u`&&localStorage.setItem(`${this.key()}:outbox`,JSON.stringify(e))}async request(e,t){let n=await this.fetcher(`${this.config.endpoint||``}/v1/sync/${e}`,{method:`POST`,credentials:`include`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json().catch(()=>({}));if(!n.ok)throw Error(r.error||`sync ${e} failed (${n.status})`);return r}async start(){this.status.set(`connecting`);try{if(!this.sessionId){let e={resources:this.config.scope.resources||this.config.scope.collections?.map(e=>`flow://${this.config.device.application_id}/${e}/*`)||[],fields:this.config.scope.fields||{}},t=await this.request(`session`,{device:{...this.config.device,created_at:Math.floor(Date.now()/1e3)},scope:e,offline_grant:this.config.offlineGrant});this.sessionId=t.session_id,this.cursor=t.cursor,this.persist()}return await this.flush(),this.timer=setInterval(()=>void this.flush(),5e3),this}catch(e){throw this.error=String(e),this.status.set(`degraded`),this.persist(),e}}async stop(){this.timer&&clearInterval(this.timer),this.sessionId&&await this.request(`close`,{session_id:this.sessionId}),this.status.set(`offline`)}enqueue(e){let t=this.readOutbox();return t.some(t=>t.operation_id===e.operation_id)||(t.push(e),this.writeOutbox(t)),e.operation_id}async flush(){if(!(!this.sessionId||!this.cursor)){this.status.set(`syncing`);try{let e=this.readOutbox();if(e.length){let t=await this.request(`push`,{session_id:this.sessionId,operations:e}),n=new Set([...t.acknowledgements.map(e=>e.operation_id),...t.rejections.filter(e=>!e.retryable).map(e=>e.operation_id)]);this.writeOutbox(e.filter(e=>!n.has(e.operation_id))),this.cursor=t.cursor}let t=await this.request(`pull`,{session_id:this.sessionId,cursor:this.cursor,limit:250});this.cursor=t.cursor,await this.request(`ack`,{session_id:this.sessionId,cursor:this.cursor}),this.error=void 0,this.status.set(`synced`),this.persist()}catch(e){this.error=String(e),this.status.set(typeof navigator<`u`&&!navigator.onLine?`offline`:`degraded`),this.persist()}}}pending(){return this.readOutbox()}conflicts(){return this.readOutbox().filter(e=>e.status===`CONFLICTED`)}lastCursor(){return this.cursor}lastError(){return this.error}},Yr=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`,...t?.headers||{}},...t}),r=n.status===204?void 0:await n.json();if(!n.ok)throw Error(r?.error||`Workload request failed (${n.status})`);return r}create(e){return this.json(`/v1/workloads`,{method:`POST`,body:JSON.stringify({...e,created_at:e.created_at||Math.floor(Date.now()/1e3)})})}list(e){return this.json(`/v1/workloads?application_id=${encodeURIComponent(e)}`)}inspect(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}`)}claim(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/claim`,{method:`POST`,body:JSON.stringify(t)})}start(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/start`,{method:`POST`,body:JSON.stringify(t)})}heartbeat(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/heartbeat`,{method:`POST`,body:JSON.stringify(t)})}checkpoint(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/checkpoint`,{method:`POST`,body:JSON.stringify(t)})}complete(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/complete`,{method:`POST`,body:JSON.stringify(t)})}fail(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/fail`,{method:`POST`,body:JSON.stringify(t)})}confirmCancelled(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/cancelled`,{method:`POST`,body:JSON.stringify(t)})}executionContext(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/context`,{method:`POST`,body:JSON.stringify(t)})}cancel(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/cancel`,{method:`POST`,body:JSON.stringify({grant:t})})}retry(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/retry`,{method:`POST`,body:JSON.stringify({grant:t})})}history(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}/history`)}result(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}/result`)}},Xr=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`,...t?.headers||{}},...t}),r=n.status===204?void 0:await n.json();if(!n.ok)throw Error(r?.error||`Mesh request failed (${n.status})`);return r}},Zr=class extends Xr{register(e){return this.json(`/v1/workers/register`,{method:`POST`,body:JSON.stringify({...e,registered_at:e.registered_at||Math.floor(Date.now()/1e3)})})}list(e){return this.json(`/v1/workers?application_id=${encodeURIComponent(e)}`)}inspect(e){return this.json(`/v1/workers/${encodeURIComponent(e)}`)}heartbeat(e,t,n){return this.json(`/v1/workers/${encodeURIComponent(e)}/heartbeat`,{method:`POST`,body:JSON.stringify({heartbeat:t,grant:n})})}drain(e,t){return this.json(`/v1/workers/${encodeURIComponent(e)}/drain`,{method:`POST`,body:JSON.stringify({grant:t})})}recover(e,t){return this.json(`/v1/workers/${encodeURIComponent(e)}/recover`,{method:`POST`,body:JSON.stringify({grant:t})})}reconcile(e,t,n){return this.json(`/v1/workers/${encodeURIComponent(e)}/reconcile`,{method:`POST`,body:JSON.stringify({reconciliation:t,grant:n})})}},Qr=class extends Xr{list(e){return this.json(`/v1/worker-pools?application_id=${encodeURIComponent(e)}`)}create(e,t){return this.json(`/v1/worker-pools`,{method:`POST`,body:JSON.stringify({pool:e,grant:t})})}inspect(e){return this.json(`/v1/worker-pools/${encodeURIComponent(e)}`)}},$r=class extends Xr{async status(e){let[t,n]=await Promise.all([new Zr(this.baseUrl,this.fetcher).list(e),new Qr(this.baseUrl,this.fetcher).list(e)]);return{workers:t.workers,pools:n.pools,ready:t.workers.filter(e=>e.lifecycle===`READY`).length,busy:t.workers.filter(e=>e.lifecycle===`BUSY`).length}}eligibleWorkers(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}/eligible-workers`)}},ei=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Artifact request failed (${n.status})`);return r}async create(e){let t=new URLSearchParams({application_id:e.applicationId,kind:typeof e.kind==`string`?e.kind:`OTHER(${e.kind.OTHER})`,name:e.name,content_type:e.contentType,producer_kind:e.producerKind||`human`,producer_id:e.producerId||``});for(let n of e.parents||[])t.append(`parents`,n);for(let[n,r]of Object.entries({supersedes:e.supersedes,revision:e.revision,workload:e.workload,execution:e.execution}))r&&t.set(n,r);return this.json(`/v1/artifacts?${t}`,{method:`POST`,headers:{"content-type":e.contentType},body:(e.content instanceof Blob||e.content instanceof Uint8Array,e.content)})}list(e){return this.json(`/v1/artifacts?application_id=${encodeURIComponent(e)}`)}get(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}`)}async content(e){let t=await this.fetcher(`${this.baseUrl}/v1/artifacts/${encodeURIComponent(e)}/content`,{credentials:`include`});if(!t.ok)throw Error(`Artifact content failed (${t.status})`);return new Uint8Array(await t.arrayBuffer())}provenance(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/provenance`)}parents(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/parents`)}children(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/children`)}archive(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/archive`,{method:`POST`})}restore(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/restore`,{method:`POST`})}},ti=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Bundle request failed (${n.status})`);return r}export(e,t={}){return this.json(`/v1/bundles/export`,{method:`POST`,body:JSON.stringify({application_id:e,options:t})})}inspect(e){return this.json(`/v1/bundles/${encodeURIComponent(e)}`)}verify(e){return this.json(`/v1/bundles/${encodeURIComponent(e)}/verify`,{method:`POST`})}planImport(e,t,n,r){return this.json(`/v1/bundles/import/plan`,{method:`POST`,body:JSON.stringify({bundle:e,mode:t,destination_tenant:n,destination_application:r})})}import(e,t,n,r){return this.json(`/v1/bundles/import/apply`,{method:`POST`,body:JSON.stringify({bundle:e,mode:t,destination_tenant:n,destination_application:r})})}},ni=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Release request failed (${n.status})`);return r}create(e){return this.json(`/v1/releases`,{method:`POST`,body:JSON.stringify({manifest:e})})}list(e){return this.json(`/v1/releases?application_id=${encodeURIComponent(e)}`)}get(e){return this.json(`/v1/releases/${encodeURIComponent(e)}`)}verify(e){return this.json(`/v1/releases/${encodeURIComponent(e)}/verify`,{method:`POST`})}promote(e,t,n){return this.json(`/v1/releases/${encodeURIComponent(e)}/promote`,{method:`POST`,body:JSON.stringify({application_id:t,environment:n})})}plan(e,t,n){return this.json(`/v1/deployments/plan`,{method:`POST`,body:JSON.stringify({release_id:e,environment:t,rollback_target:n})})}deploy(e){return this.json(`/v1/deployments`,{method:`POST`,body:JSON.stringify({plan:e})})}status(e){return this.json(`/v1/deployments/${encodeURIComponent(e)}`)}health(e){return this.json(`/v1/deployments/${encodeURIComponent(e)}/health`)}stop(e){return this.json(`/v1/deployments/${encodeURIComponent(e)}/stop`,{method:`POST`})}},ri=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Observe request failed (${n.status})`);return r}events(e){return this.json(`/v1/observability/events?application_id=${encodeURIComponent(e)}`)}cause(e){return this.json(`/v1/observability/causes/${encodeURIComponent(e)}`)}workload(e){return this.json(`/v1/observability/workloads/${encodeURIComponent(e)}/timeline`)}execution(e){return this.json(`/v1/observability/executions/${encodeURIComponent(e)}/timeline`)}revision(e){return this.json(`/v1/observability/revisions/${encodeURIComponent(e)}/timeline`)}append(e){return this.json(`/v1/observability/events`,{method:`POST`,body:JSON.stringify({event:e})})}},ii=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Provider request failed (${n.status})`);return r}list(){return this.json(`/v1/providers`)}inspect(e){return this.json(`/v1/providers/${encodeURIComponent(e)}`)}install(e,t,n){return this.json(`/v1/providers`,{method:`POST`,body:JSON.stringify({manifest:e,tenant_id:t,application_id:n})})}enable(e){return this.status(e,`ENABLED`)}disable(e){return this.status(e,`DISABLED`)}revoke(e){return this.status(e,`REVOKED`)}status(e,t){return this.json(`/v1/providers/${encodeURIComponent(e)}/status`,{method:`POST`,body:JSON.stringify({status:t})})}health(e){return this.json(`/v1/providers/${encodeURIComponent(e)}/health`)}dependencies(e){return this.json(`/v1/providers/${encodeURIComponent(e)}/dependencies`)}},ai=()=>typeof window<`u`&&window.document!==void 0,oi=e=>typeof process<`u`?{}[e]:void 0,si=()=>{let e=globalThis.crypto;if(typeof e?.randomUUID==`function`)return e.randomUUID();let t=new Uint8Array(16);if(typeof e?.getRandomValues==`function`)e.getRandomValues(t);else for(let e=0;e<t.length;e+=1)t[e]=Math.floor(Math.random()*256);t[6]=t[6]&15|64,t[8]=t[8]&63|128;let n=Array.from(t,e=>e.toString(16).padStart(2,`0`)).join(``);return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`},ci=class{constructor(){this.id=null,this.identityFile=null}getId(){if(this.id)return this.id;try{if(ai()){let e=globalThis.localStorage?.getItem(`feltdb.install-id`);return this.id=e&&this.isValidUUID(e)?e:si(),globalThis.localStorage?.setItem(`feltdb.install-id`,this.id),this.id}return this.id=si(),this.id}catch{return this.id||=si(),this.id}}isValidUUID(e){return/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e)}},li=class{constructor(e=`0.5.7`){this.batchSize=10,this.eventQueue=[],this.flushTimer=null,this.runtime=`node`,this.coreVersion=e,this.identity=new ci,this.enabled=oi(`FELTDB_TELEMETRY`)!==`0`&&oi(`FELTDB_TELEMETRY`)!==`false`,ai()&&(this.runtime=`browser`)}emit(e){if(this.enabled)try{let t={event:e,installation_id:this.identity.getId(),core_version:this.coreVersion,runtime:this.runtime,os:this.getOS(),timestamp:new Date().toISOString()};this.eventQueue.push(t),this.eventQueue.length>=this.batchSize?this.flush():this.scheduleFlush()}catch{}}async flush(){if(this.eventQueue.length===0||!this.enabled)return;this.flushTimer&&=(clearTimeout(this.flushTimer),null);let e=this.eventQueue.splice(0,this.batchSize);try{await this.sendEvents(e)}catch{}}scheduleFlush(){this.flushTimer||!this.enabled||(this.flushTimer=setTimeout(()=>{this.flush().catch(()=>{})},5e3))}async sendEvents(e){let t=oi(`FELTDB_TELEMETRY_ENDPOINT`)||`https://kendel.feltdb.com/api/v1/telemetry/events`,n=new AbortController,r=setTimeout(()=>n.abort(),3e3);try{(await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({events:e}),signal:n.signal})).ok}catch{}finally{clearTimeout(r)}}getOS(){if(ai())return`browser`;let e=typeof process<`u`?process.platform:`unknown`;switch(e){case`darwin`:return`macos`;case`linux`:return`linux`;case`win32`:return`windows`;case`freebsd`:return`freebsd`;default:return e}}enable(){this.enabled=!0}disable(){this.enabled=!1,this.eventQueue=[],this.flushTimer&&=(clearTimeout(this.flushTimer),null)}isEnabled(){return this.enabled}async forceFlush(){for(;this.eventQueue.length>0;)await this.flush()}},ui=null;function R(e){return ui||=new li(e),ui}function di(e){R().emit(e)}function fi(e){if(!e?.namespace?.trim())throw Error(`createFeltDB requires a non-empty namespace`);return new pi(e.server?new I(e.server):`browser`in e&&e.browser?new wr(e.namespace):`path`in e&&e.path?new Fr(e.path):new Cr(e.namespace))}var pi=class{constructor(e){this.collections=new Map,this.cells=new Map,this.capabilityWorkers=new Map,this.workloads=new Yr,this.artifacts=new ei,this.bundle=new ti,this.releases=new ni,this.observe=new ri,this.providers=new ii,this.workers=new Zr,this.workerPools=new Qr,this.mesh=new $r,this.jsDb=e,this.runtimeInfo=this.detectRuntime(),this.agentRegistry=new yr;let t={persistent:this.runtimeInfo.persistent,executionTimeoutMs:3e4,supportsReactiveTriggers:!0,defaultRetryPolicy:{maxAttempts:3,backoffMs:1e3}};this.agentRuntime=new xr(this.agentRegistry,t),di(`initialize`)}detectRuntime(){let e=typeof window<`u`&&typeof document<`u`,t=typeof globalThis<`u`&&`versions`in globalThis&&`node`in globalThis.versions,n=this.jsDb instanceof Cr,r=this.jsDb instanceof I,i=this.jsDb instanceof wr,a=`memory`,o=!1;return r?(a=`remote`,o=!0):n?a=`memory`:i?(a=`indexeddb`,o=!0):t&&(a=`file`,o=!0),{runtime:r?`remote`:i||e?`browser`:t?`node`:`wasm`,storage:a,persistent:o,reactive:!0,durable:o,version:`0.1.0`,supportsCheckpointing:o,supportsLifecycle:e||i}}runtime(){return{...this.runtimeInfo}}collection(e){return this.collections.has(e)||this.collections.set(e,new mr(this.jsDb,e)),this.collections.get(e)}cell(e){return this.cells.has(e)||this.cells.set(e,new gr(this.jsDb,e)),this.cells.get(e)}async acquire(e,t){return this.jsDb instanceof I?this.jsDb.acquire(e,t):this.collection(e).get(t)}async search(e,t,n=50){if(this.jsDb instanceof I)return this.jsDb.search(e,t,n);let r=t.toLowerCase();return(await this.collection(e).all()).filter(e=>JSON.stringify(e).toLowerCase().includes(r)).slice(0,n)}async defineCapability(e,t){if(!(this.jsDb instanceof I))throw Error(`Distributed capabilities require a server runtime`);return this.jsDb.command(`/capabilities/${encodeURIComponent(e)}`,{steps:t})}registerCapabilityWorker(e,t){if(this.jsDb instanceof I)throw Error(`Remote capability workers are installed on the server`);return this.capabilityWorkers.set(e,t),()=>this.capabilityWorkers.delete(e)}async executeCapability(e,t){if(this.jsDb instanceof I)return this.jsDb.command(`/capabilities/${encodeURIComponent(e)}/execute`,t);let n=this.capabilityWorkers.get(e);if(!n)throw Error(`No embedded capability worker registered for ${e}`);let r=`cap-${e}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,i=this.collection(`_flow_executions`);await i.insert({id:r,capability:e,input:t,status:`running`,owner:this.instanceId(),started_at:Date.now()},r);try{let e=await n(t);return await i.update(r,{status:`completed`,output:e,completed_at:Date.now()}),e}catch(e){throw await i.update(r,{status:`failed`,error:e instanceof Error?e.message:String(e),completed_at:Date.now()}),e}}async changeClusterMembership(e,t){if(!(this.jsDb instanceof I))throw Error(`Cluster membership requires a server runtime`);return this.jsDb.command(`/cluster/members`,{expected_epoch:e,peers:t})}async deployFlowSpec(e,t,n=!1){let r=Vr(e).filter(e=>e.severity===`error`);if(r.length)throw Error(r.map(e=>e.message).join(`; `));let i=this.collection(`_flow_apps`),a=await i.get(e.app),o=(a?.version??0)+1;if(t!==void 0&&(a?.version??0)!==t)throw Error(`FlowSpec version conflict: expected ${t}, found ${a?.version??0}`);let s=Gr(a?.spec??Kr(e.app),e),c=s.filter(e=>e.safety===`destructive`);if(c.length&&!n)throw Error(`Destructive migration requires explicit approval: ${c.map(e=>e.target).join(`, `)}`);let l={id:e.app,app:e.app,version:o,status:`deploying`,spec:e,migration:s,deployed_at:Date.now()};a?await i.update(e.app,l):await i.insert(l,e.app);let u=(t,n)=>`${e.app}-${t}-${n}`.replace(/[^A-Za-z0-9_-]/g,`_`),d=async(t,n,r,i)=>{let a=this.collection(t),s=new Set(i.map(e=>e.name??e.event??`unnamed`));for(let e of r){let t=e.name??e.event??`unnamed`;s.has(t)||await a.delete(u(n,t))}for(let t of i){let r=t.name??t.event??`unnamed`,i=u(n,r),s={id:i,app:e.app,version:o,...t};await a.get(i)?await a.update(i,s):await a.insert(s,i)}},f=a?.spec??Kr(e.app);if(await d(`_flow_collection_models`,`collection`,f.collections,e.collections),await d(`_flow_capability_models`,`capability`,f.capabilities,e.capabilities),await d(`_flow_trigger_models`,`trigger`,f.triggers,e.triggers),await d(`_flow_policy_models`,`policy`,f.policies,e.policies),await d(`_flow_schedule_models`,`schedule`,f.schedules,e.schedules),this.jsDb instanceof I){for(let t of f.workflows)e.workflows.some(e=>e.name===t.name)||await this.collection(`_flow_workflows`).delete(u(`workflow`,t.name));for(let t of f.agents)e.agents.some(e=>e.name===t.name)||await this.collection(`_flow_agents`).delete(u(`agent`,t.name));for(let t of e.workflows)await this.defineWorkflow(u(`workflow`,t.name),t.steps.map(e=>e.name));for(let t of e.agents){let n=t.statements.filter(e=>e.startsWith(`capability `)).map(e=>e.slice(11).trim());await this.defineStateAgent(u(`agent`,t.name),n,{flowspec_app:e.app,flowspec_version:o})}}else await d(`_flow_workflows`,`workflow`,f.workflows,e.workflows),await d(`_flow_agents`,`agent`,f.agents,e.agents);let p={...l,status:`active`};return await i.update(e.app,p),await this.collection(`_flow_app_versions`).insert({id:`${e.app}-${o}`,app:e.app,version:o,spec:e,migration:s,deployed_at:p.deployed_at},`${e.app}-${o}`),{app:e.app,version:o,status:`active`}}async auditEvents(){return this.jsDb.audit_events?await this.jsDb.audit_events():[]}async exportOperations(e=0){if(!this.jsDb.export_operations)throw Error(`This runtime uses server-managed replication`);return await this.jsDb.export_operations(e)}async applyOperations(e){if(!this.jsDb.apply_remote_operations)throw Error(`This runtime uses server-managed replication`);return await this.jsDb.apply_remote_operations(e)}async synchronizeWith(e){let t=await this.exportOperations(),n=await e.exportOperations();await this.addSyncPeer(e.instanceId()),await e.addSyncPeer(this.instanceId());let r=await e.applyOperations(t),i=await this.applyOperations(n);return{sent:t.length,received:n.length,applied:i.applied+r.applied,ignored:i.ignored+r.ignored}}async executeCapabilityWithFailover(e,t,n=[]){let r=this.collection(`_flow_capability_routes`),i=`route-${e}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,a=[this,...n],o=[];await r.insert({id:i,capability:e,status:`routing`,input:t,candidates:a.map(e=>e.instanceId()),started_at:Date.now()},i);for(let n of a)try{let a=await n.executeCapability(e,t);return await r.update(i,{status:`completed`,provider:n.instanceId(),attempts:o.length+1,failures:o,completed_at:Date.now()}),{output:a,provider:n.instanceId(),attempts:o.length+1}}catch(e){o.push({provider:n.instanceId(),error:e instanceof Error?e.message:String(e)})}throw await r.update(i,{status:`failed`,attempts:o.length,failures:o,completed_at:Date.now()}),Error(`No provider could execute capability ${e}: ${o.map(e=>e.error).join(`; `)}`)}async recordProvenance(e,t){if(!(this.jsDb instanceof I))throw Error(`Causal provenance requires a server runtime`);return this.jsDb.provenance(e,t)}async storeContent(e){if(!(this.jsDb instanceof I))throw Error(`Durable content storage requires a server runtime`);return this.jsDb.storeContent(e)}async acquireContent(e){if(!(this.jsDb instanceof I))throw Error(`Network content acquisition requires a server runtime`);return this.jsDb.acquireContent(e)}async defineWorkflow(e,t){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflows/${encodeURIComponent(e)}`,{steps:t})}async startWorkflow(e,t=null){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflows/${encodeURIComponent(e)}/runs`,{input:t})}async claimWorkflowStep(e,t,n,r=3e4){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflow-runs/${encodeURIComponent(e)}/steps/${encodeURIComponent(t)}/claim`,{worker:n,lease_ms:r})}async completeWorkflowStep(e,t,n,r=null){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflow-runs/${encodeURIComponent(e)}/steps/${encodeURIComponent(t)}/complete`,{claim_id:n,result:r})}async defineStateAgent(e,t=[],n=null){if(!(this.jsDb instanceof I))throw Error(`Durable agent coordination requires a server runtime`);return this.jsDb.command(`/agents/${encodeURIComponent(e)}`,{capabilities:t,constraints:n})}async startStateAgent(e,t,n=null){if(!(this.jsDb instanceof I))throw Error(`Durable agent coordination requires a server runtime`);return this.jsDb.command(`/agents/${encodeURIComponent(e)}/runs`,{goal:t,input:n})}defineAgent(e){let t=_r(e.name,e.version);return this.agentRegistry.register(t,e),t}agent(e){return this.agentRegistry.getByName(e)?.agentRef}getAgentRegistry(){return this.agentRegistry}getAgentRuntime(){return this.agentRuntime}async createAgentExecution(e,t,n){let r=await this.agentRuntime.createExecution(this,e,t,n);return await this.collection(`_flow_agent_executions`).insert(this.agentExecutionRecord(r),r.executionId),r}agentExecutionRecord(e){return{...e,id:e.executionId,agentRef:e.agentRef.toString()}}async startAgentExecution(e,t=this.instanceId()){await this.agentRuntime.start(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async transitionAgentExecution(e,t){await this.agentRuntime.transition(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async completeAgentExecution(e,t){await this.agentRuntime.complete(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async failAgentExecution(e,t){await this.agentRuntime.fail(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async close(){for(let e of this.collections.values())e.close();this.collections.clear(),await this.jsDb.close?.()}sync(e){if(e)return new Jr(e);let t=this.jsDb.sync_info();if(!t.success||!t.data)throw Error(t.error||`Failed to get sync info`);return JSON.parse(t.data)}async addSyncPeer(e){let t=this.jsDb.add_sync_peer(e);if(!t.success)throw Error(t.error||`Failed to add peer`)}async removeSyncPeer(e){let t=this.jsDb.remove_sync_peer(e);if(!t.success)throw Error(t.error||`Failed to remove peer`)}async getPendingForPeer(e,t){let n=this.jsDb.get_pending_for_peer(e,t);if(!n.success||!n.data)throw Error(n.error||`Failed to get pending operations`);return JSON.parse(n.data)}async acknowledgePeerOperations(e,t){let n=this.jsDb.acknowledge_peer_operations(e,t);if(!n.success)throw Error(n.error||`Failed to acknowledge operations`)}instanceId(){return this.jsDb.instance_id()}getSequence(){return this.jsDb.get_sequence()}async registerTrigger(e){}async scheduleCron(e){}async getPendingExecutions(){return[]}async completeExecution(e,t){}provenance(e){let[t,...n]=e.split(`://`)[1]?.split(`/`)||[],r={id:e,type:`Record`,label:n.join(`/`)||e,created_ms:Date.now()};return{root:r,nodes:[r],edges:[]}}health(){let e=this.sync(),t=this.runtime(),n=e.is_connected&&e.pending_operations===0?`healthy`:`degraded`,r=[];e.pending_operations>0&&r.push({severity:`info`,component:`sync`,message:`${e.pending_operations} pending operations`}),e.is_connected||r.push({severity:`warning`,component:`sync`,message:`Network disconnected`}),e.conflicts_detected>0&&r.push({severity:`warning`,component:`sync`,message:`${e.conflicts_detected} conflicts detected`});let i=r.length>0?`degraded`:`healthy`;return{runtime:{status:`healthy`,wasm:t.runtime===`wasm`||t.runtime===`browser`,reactive:t.reactive},storage:{status:`healthy`,backend:t.storage,persistent:t.persistent,durable:t.durable},sync:{status:n,connected:e.is_connected,peers:e.connected_peers.length,pendingOperations:e.pending_operations},fabric:{status:`healthy`,references:0,peers:e.connected_peers.length},capabilities:{status:`healthy`,count:0,available:0},execution:{status:`healthy`,pending:0,running:0,failed:0},workflow:{status:`healthy`,total:0,active:0},status:i,issues:r}}async allocateSequence(e){if(typeof this.jsDb.allocateSequence!=`function`)throw Error(`allocateSequence is not supported by ${this.runtimeInfo.storage} backend. Only FileJsDb (Node.js) supports atomic sequence allocation.`);return this.jsDb.allocateSequence(e)}async putIfAbsent(e,t){if(typeof this.jsDb.putIfAbsent!=`function`)throw Error(`putIfAbsent is not supported by ${this.runtimeInfo.storage} backend. Only FileJsDb (Node.js) supports durable idempotent mutation.`);return this.jsDb.putIfAbsent(e,t)}async cas(e){if(typeof this.jsDb.cas!=`function`)throw Error(`cas is not supported by ${this.runtimeInfo.storage} backend. Only FileJsDb (Node.js) supports compare-and-set with version detection.`);return this.jsDb.cas(e)}},mi;(function(e){e.Insert=`Insert`,e.Update=`Update`,e.Delete=`Delete`,e.Query=`Query`,e.Upsert=`Upsert`})(mi||={});var hi;(function(e){e.Pending=`Pending`,e.Running=`Running`,e.Succeeded=`Succeeded`,e.Failed=`Failed`,e.RetryScheduled=`RetryScheduled`,e.DeadLettered=`DeadLettered`})(hi||={});var gi;(function(e){e.OK=`OK`,e.CONFLICT=`CONFLICT`,e.PRECONDITION_FAILED=`PRECONDITION_FAILED`,e.TOO_BUSY=`TOO_BUSY`,e.INTERNAL_ERROR=`INTERNAL_ERROR`})(gi||={});var _i=Ur(Kr(`Application`));function vi({db:e,namespace:t=`default`,projectSpec:n,onSpecChange:r}){let i=`feltdb:studio:draft:${t}`,a=(0,g.useRef)((()=>{if(typeof window>`u`)return _i;let e=window.localStorage.getItem(i);if(!e)return _i;try{return Br(e),e}catch{return _i}})()),o=(0,g.useRef)(a.current!==_i),[s,c]=(0,g.useState)(a.current),[l,u]=(0,g.useState)(()=>Br(a.current)),[d,f]=(0,g.useState)([]),[p,m]=(0,g.useState)([]),[h,_]=(0,g.useState)(`Draft is valid`),[v,y]=(0,g.useState)(0),[b,x]=(0,g.useState)(null),[S,C]=(0,g.useState)(null),[w,T]=(0,g.useState)(!1),[ee,te]=(0,g.useState)(!1),[E,D]=(0,g.useState)({url:``,namespace:t,token:``,allowDestructive:!1}),ne=(0,g.useRef)(null),re=p.length?p[p.length-1].source:Ur(Kr(l.app)),ie=(0,g.useMemo)(()=>Wr(Br(re),l),[re,l]),ae=(0,g.useMemo)(()=>Gr(Br(re),l),[re,l]);(0,g.useEffect)(()=>{if(!e||n)return;let t=!1;return(async()=>{try{let n=await e.collection(`_flow_apps`).all(),r=n.find(e=>e.status===`active`)??n[0];if(!r||t)return;let i=Ur(r.spec);o.current||(u(r.spec),c(i)),y(r.version??0);let a=(await e.collection(`_flow_app_versions`).all()).filter(e=>e.app===r.app).sort((e,t)=>e.version-t.version);t||(m(a.map(e=>({version:e.version,source:Ur(e.spec),savedAt:e.deployed_at}))),_(`Loaded ${r.app} v${r.version}`))}catch(e){t||_(`Could not load deployed model: ${e instanceof Error?e.message:String(e)}`)}})(),()=>{t=!0}},[e,n]),(0,g.useEffect)(()=>{let e=window.setTimeout(()=>window.localStorage.setItem(i,s),200);return()=>window.clearTimeout(e)},[i,s]);let O=e=>{c(e);try{let t=Br(e),n=Vr(t);u(t),r?.(t),f(n),_(n.some(e=>e.severity===`error`)?`Model has validation errors`:`Draft is valid`)}catch(e){f([{severity:`error`,message:e instanceof Error?e.message:String(e)}]),_(`DSL parse failed`)}};(0,g.useEffect)(()=>{if(!n)return;let e=Ur(n);c(e),u(n),f(Vr(n)),_(`Loaded ${n.app} project model`)},[n]);let oe=e=>{u(e),O(Ur(e))},se=()=>{if(!S)return C({name:``});let e=S.name.trim();if(!/^[A-Z][A-Za-z0-9_]*$/.test(e))return C({...S,error:`Use a capitalized name with no spaces.`});if(l.collections.some(t=>t.name===e))return C({...S,error:`That collection already exists.`});oe({...l,collections:[...l.collections,{name:e,fields:[],indexes:[]}]}),C(null)},ce=e=>x({collection:e,name:``,type:`text`,reference:``,optional:!1}),le=()=>{if(!b)return;let e=b.name.trim(),t=l.collections.find(e=>e.name===b.collection);if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e))return x({...b,error:`Use a letter-led name with no spaces.`});if(t?.fields.some(t=>t.name===e))return x({...b,error:`That field already exists.`});if([`ref`,`enum`,`array`,`map`,`vector`].includes(b.type)&&!b.reference.trim())return x({...b,error:`Configure this field type.`});let n=b.type===`ref`?`ref ${b.reference}`:b.type===`enum`?`enum(${b.reference.split(`,`).map(e=>e.trim()).filter(Boolean).join(`,`)})`:b.type===`array`?`array<${b.reference.trim()}>`:b.type===`map`?`map<${b.reference.trim()}>`:b.type===`vector`?`vector<${b.reference.trim()}>`:b.type;oe({...l,collections:l.collections.map(t=>t.name===b.collection?{...t,fields:[...t.fields,{name:e,type:n,optional:b.optional}]}:t)}),x(null)},k=()=>{let e=[...p,{version:p.length+1,source:s,savedAt:Date.now()}];m(e),_(`Saved local revision v${e.length}`)},ue=async()=>{if(!e)return _(`Local embedded storage is unavailable`);if(d.some(e=>e.severity===`error`))return _(`Resolve validation errors before deploying`);if(ae.filter(e=>e.safety===`destructive`).length&&!w)return _(`Review and approve destructive local changes before applying`);try{let t=await e.deployFlowSpec(l,v,w),n=[...p,{version:t.version,source:s,savedAt:Date.now()}];m(n),y(t.version),T(!1),_(`Applied locally as ${t.app} v${t.version}`)}catch(e){_(`Local apply failed: ${e instanceof Error?e.message:String(e)}`)}},de=async()=>{if(!E.url.trim()||!E.token.trim())return D({...E,error:`Cloud URL and API key are required.`});if(d.some(e=>e.severity===`error`))return D({...E,error:`Resolve validation errors before publishing.`});D({...E,publishing:!0,error:void 0});let e=fi({namespace:E.namespace.trim()||t,server:{url:E.url.trim().replace(/\/$/,``),token:E.token}});try{let t=await e.collection(`_flow_apps`).get(l.app),n=Gr(t?.spec??Kr(l.app),l).filter(e=>e.safety===`destructive`);if(n.length&&!E.allowDestructive)return D({...E,publishing:!1,destructive:n.map(e=>e.target),error:`Review and approve destructive changes: ${n.map(e=>e.target).join(`, `)}`});let r=await e.deployFlowSpec(l,t?.version??0,E.allowDestructive);window.sessionStorage.setItem(`feltdb-token:${E.url.trim()}`,E.token),D({...E,publishing:!1,token:``,error:void 0}),te(!1),_(`Published ${r.app} v${r.version} to cloud`)}catch(e){D({...E,publishing:!1,error:e instanceof Error?e.message:String(e)})}finally{await e.close()}},fe=()=>{let e=URL.createObjectURL(new Blob([s],{type:`text/plain`})),t=document.createElement(`a`);t.href=e,t.download=`feltdb.flow`,t.click(),URL.revokeObjectURL(e)},pe=async e=>{e&&O(await e.text())},me=[[`Data`,l.collections.map(e=>e.name)],[`Capabilities`,l.capabilities.map(e=>e.name)],[`Agents`,l.agents.map(e=>e.name)],[`Workflows`,l.workflows.map(e=>e.name)],[`Triggers`,l.triggers.map(e=>e.event)],[`Policies`,l.policies.map(e=>e.name)],[`Schedules`,l.schedules.map(e=>e.name)]];return(0,P.jsxs)(`div`,{className:`application-designer`,children:[(0,P.jsxs)(`header`,{className:`designer-header`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`span`,{className:`eyebrow`,children:`Application fabric`}),(0,P.jsx)(`h1`,{children:l.app}),(0,P.jsx)(`p`,{children:`One model for state, intelligence, automation, security, and placement.`})]}),(0,P.jsxs)(`div`,{className:`designer-actions`,children:[(0,P.jsx)(`input`,{ref:ne,hidden:!0,type:`file`,accept:`.flow,text/plain`,onChange:e=>void pe(e.target.files?.[0])}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>ne.current?.click(),children:`Import`}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:fe,children:`Export`}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:k,children:`Version`}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>void ue(),children:`Apply locally`}),(0,P.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>te(e=>!e),children:`Publish to cloud`})]})]}),ae.some(e=>e.safety===`destructive`)&&(0,P.jsxs)(`label`,{className:`local-destructive`,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:w,onChange:e=>T(e.target.checked)}),(0,P.jsxs)(`span`,{children:[`Approve destructive local changes: `,ae.filter(e=>e.safety===`destructive`).map(e=>e.target).join(`, `)]})]}),ee&&(0,P.jsxs)(`form`,{className:`cloud-publisher`,onSubmit:e=>{e.preventDefault(),de()},children:[(0,P.jsxs)(`div`,{className:`cloud-publisher-heading`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`span`,{className:`eyebrow`,children:`Cloud release`}),(0,P.jsx)(`h2`,{children:`Publish this application model`}),(0,P.jsx)(`p`,{children:`FeltDB compares the cloud version, plans the migration, and publishes atomically.`})]}),(0,P.jsx)(`button`,{type:`button`,"aria-label":`Close cloud publisher`,onClick:()=>te(!1),children:`×`})]}),(0,P.jsxs)(`div`,{className:`cloud-fields`,children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`FeltDB Cloud URL`}),(0,P.jsx)(`input`,{type:`url`,placeholder:`https://your-instance.feltdb.cloud`,value:E.url,onChange:e=>D({...E,url:e.target.value,error:void 0,destructive:void 0,allowDestructive:!1})})]}),(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Namespace`}),(0,P.jsx)(`input`,{value:E.namespace,onChange:e=>D({...E,namespace:e.target.value,error:void 0,destructive:void 0,allowDestructive:!1})})]}),(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`API key`}),(0,P.jsx)(`input`,{type:`password`,autoComplete:`off`,placeholder:`Stored for this browser session only`,value:E.token,onChange:e=>D({...E,token:e.target.value,error:void 0})})]})]}),(E.destructive?.length||ae.some(e=>e.safety===`destructive`))&&(0,P.jsxs)(`label`,{className:`cloud-destructive`,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:E.allowDestructive,onChange:e=>D({...E,allowDestructive:e.target.checked})}),(0,P.jsxs)(`span`,{children:[`I reviewed and approve destructive model changes`,E.destructive?.length?`: ${E.destructive.join(`, `)}`:`.`]})]}),E.error&&(0,P.jsx)(`div`,{className:`cloud-error`,role:`alert`,children:E.error}),(0,P.jsxs)(`div`,{className:`cloud-actions`,children:[(0,P.jsx)(`button`,{type:`button`,className:`btn btn-ghost`,onClick:()=>te(!1),children:`Cancel`}),(0,P.jsx)(`button`,{className:`btn btn-primary`,disabled:E.publishing,type:`submit`,children:E.publishing?`Publishing…`:`Review and publish`})]})]}),(0,P.jsxs)(`div`,{className:`designer-status ${d.some(e=>e.severity===`error`)?`error`:``}`,children:[(0,P.jsx)(`span`,{children:h}),(0,P.jsxs)(`span`,{children:[l.collections.length,` collections · `,l.workflows.length,` workflows · `,p.length?`v${p.length}`:`draft`]})]}),(0,P.jsxs)(`div`,{className:`designer-grid`,children:[(0,P.jsxs)(`aside`,{className:`model-tree`,children:[(0,P.jsxs)(`div`,{className:`panel-title`,children:[(0,P.jsx)(`span`,{children:`Application`}),(0,P.jsx)(`button`,{"aria-label":`Add collection`,onClick:()=>C({name:``}),children:`+`})]}),S&&(0,P.jsxs)(`form`,{className:`collection-editor`,onSubmit:e=>{e.preventDefault(),se()},onKeyDown:e=>{e.key===`Escape`&&C(null)},children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`New collection`}),(0,P.jsx)(`input`,{autoFocus:!0,placeholder:`e.g. Customer`,value:S.name,onChange:e=>C({name:e.target.value})})]}),S.error&&(0,P.jsx)(`div`,{className:`field-error`,role:`alert`,children:S.error}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`button`,{type:`button`,onClick:()=>C(null),children:`Cancel`}),(0,P.jsx)(`button`,{className:`collection-save`,type:`submit`,children:`Add`})]})]}),me.map(([e,t])=>(0,P.jsxs)(`section`,{children:[(0,P.jsx)(`h3`,{children:e}),t.length?t.map(e=>(0,P.jsx)(`div`,{className:`tree-item`,children:e},e)):(0,P.jsx)(`div`,{className:`tree-empty`,children:`None`})]},e))]}),(0,P.jsxs)(`section`,{className:`model-canvas`,children:[(0,P.jsxs)(`div`,{className:`panel-title`,children:[(0,P.jsx)(`span`,{children:`Application graph`}),(0,P.jsx)(`span`,{className:`graph-legend`,children:`intent → fabric`})]}),(0,P.jsxs)(`div`,{className:`graph-board`,children:[l.collections.map(e=>(0,P.jsxs)(`article`,{className:`model-node`,children:[(0,P.jsx)(`div`,{className:`node-kind`,children:`collection`}),(0,P.jsx)(`h3`,{children:e.name}),e.fields.map(e=>(0,P.jsxs)(`div`,{className:`node-field`,children:[(0,P.jsx)(`span`,{children:e.name}),(0,P.jsxs)(`code`,{children:[e.type,e.optional?`?`:``]})]},e.name)),b?.collection===e.name?(0,P.jsxs)(`form`,{className:`field-editor`,onSubmit:e=>{e.preventDefault(),le()},onKeyDown:e=>{e.key===`Escape`&&x(null)},children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Field name`}),(0,P.jsx)(`input`,{autoFocus:!0,value:b.name,placeholder:`e.g. publishedAt`,onChange:e=>x({...b,name:e.target.value,error:void 0})})]}),(0,P.jsxs)(`div`,{className:`field-editor-row`,children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Type`}),(0,P.jsxs)(`select`,{value:b.type,onChange:e=>x({...b,type:e.target.value,error:void 0}),children:[(0,P.jsx)(`option`,{value:`text`,children:`Text`}),(0,P.jsx)(`option`,{value:`integer`,children:`Integer`}),(0,P.jsx)(`option`,{value:`number`,children:`Number`}),(0,P.jsx)(`option`,{value:`decimal`,children:`Decimal`}),(0,P.jsx)(`option`,{value:`money`,children:`Money`}),(0,P.jsx)(`option`,{value:`bigint`,children:`Big integer`}),(0,P.jsx)(`option`,{value:`boolean`,children:`Boolean`}),(0,P.jsx)(`option`,{value:`datetime`,children:`Date & time`}),(0,P.jsx)(`option`,{value:`date`,children:`Date`}),(0,P.jsx)(`option`,{value:`time`,children:`Time`}),(0,P.jsx)(`option`,{value:`uuid`,children:`UUID`}),(0,P.jsx)(`option`,{value:`email`,children:`Email`}),(0,P.jsx)(`option`,{value:`url`,children:`URL`}),(0,P.jsx)(`option`,{value:`phone`,children:`Phone`}),(0,P.jsx)(`option`,{value:`json`,children:`JSON`}),(0,P.jsx)(`option`,{value:`object`,children:`Object`}),(0,P.jsx)(`option`,{value:`binary`,children:`Binary`}),(0,P.jsx)(`option`,{value:`file`,children:`File`}),(0,P.jsx)(`option`,{value:`geo`,children:`Geo point`}),(0,P.jsx)(`option`,{value:`enum`,children:`Enum`}),(0,P.jsx)(`option`,{value:`array`,children:`Array`}),(0,P.jsx)(`option`,{value:`map`,children:`Typed map`}),(0,P.jsx)(`option`,{value:`vector`,children:`Vector`}),(0,P.jsx)(`option`,{value:`ref`,children:`Reference`})]})]}),b.type===`ref`&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Collection`}),(0,P.jsx)(`select`,{value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0}),children:l.collections.filter(t=>t.name!==e.name).map(e=>(0,P.jsx)(`option`,{value:e.name,children:e.name},e.name))})]}),b.type===`enum`&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Values`}),(0,P.jsx)(`input`,{placeholder:`draft,active,done`,value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0})})]}),(b.type===`array`||b.type===`map`)&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Item type`}),(0,P.jsx)(`input`,{placeholder:`text, uuid, ref Project…`,value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0})})]}),b.type===`vector`&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Dimensions`}),(0,P.jsx)(`input`,{type:`number`,min:`1`,placeholder:`1536`,value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0})})]})]}),(0,P.jsxs)(`label`,{className:`field-optional`,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:b.optional,onChange:e=>x({...b,optional:e.target.checked})}),(0,P.jsx)(`span`,{children:`Optional field`})]}),b.error&&(0,P.jsx)(`div`,{className:`field-error`,role:`alert`,children:b.error}),(0,P.jsxs)(`div`,{className:`field-editor-actions`,children:[(0,P.jsx)(`button`,{type:`button`,onClick:()=>x(null),children:`Cancel`}),(0,P.jsx)(`button`,{className:`field-save`,type:`submit`,children:`Add field`})]})]}):(0,P.jsx)(`button`,{className:`node-add`,onClick:()=>ce(e.name),children:`+ field`})]},e.name)),l.workflows.map(e=>(0,P.jsxs)(`article`,{className:`model-node workflow-node`,children:[(0,P.jsx)(`div`,{className:`node-kind`,children:`workflow`}),(0,P.jsx)(`h3`,{children:e.name}),e.steps.map(e=>(0,P.jsx)(`div`,{className:`node-step`,children:e.name},e.name))]},e.name)),l.agents.map(e=>(0,P.jsxs)(`article`,{className:`model-node agent-node`,children:[(0,P.jsx)(`div`,{className:`node-kind`,children:`agent`}),(0,P.jsx)(`h3`,{children:e.name}),e.statements.map(e=>(0,P.jsx)(`div`,{className:`node-step`,children:e},e))]},e.name))]}),(0,P.jsxs)(`div`,{className:`change-strip`,children:[(0,P.jsx)(`strong`,{children:`Model diff`}),(0,P.jsxs)(`span`,{className:`added`,children:[`+ `,ie.added.join(`, `)||`none`]}),(0,P.jsxs)(`span`,{className:`changed`,children:[`~ `,ie.changed.join(`, `)||`none`]}),(0,P.jsxs)(`span`,{className:`removed`,children:[`− `,ie.removed.join(`, `)||`none`]})]})]}),(0,P.jsxs)(`section`,{className:`dsl-panel`,children:[(0,P.jsxs)(`div`,{className:`panel-title`,children:[(0,P.jsx)(`span`,{children:`Flow DSL`}),(0,P.jsx)(`span`,{children:`feltdb.flow`})]}),(0,P.jsx)(`textarea`,{"aria-label":`Flow DSL`,spellCheck:!1,value:s,onChange:e=>O(e.target.value)}),d.length>0&&(0,P.jsx)(`div`,{className:`diagnostics`,children:d.map((e,t)=>(0,P.jsxs)(`div`,{className:e.severity,children:[e.severity,`: `,e.message]},t))})]})]})]})}var z={panel:`_panel_1cbba_1`,header:`_header_1cbba_8`,createButton:`_createButton_1cbba_23`,error:`_error_1cbba_38`,createForm:`_createForm_1cbba_47`,formGroup:`_formGroup_1cbba_55`,scopeList:`_scopeList_1cbba_76`,scopeCheckbox:`_scopeCheckbox_1cbba_82`,submitButton:`_submitButton_1cbba_94`,empty:`_empty_1cbba_109`,keysList:`_keysList_1cbba_117`,keyCard:`_keyCard_1cbba_123`,keyHeader:`_keyHeader_1cbba_135`,namespace:`_namespace_1cbba_150`,status:`_status_1cbba_156`,active:`_active_1cbba_163`,expired:`_expired_1cbba_168`,keyDetails:`_keyDetails_1cbba_173`,detail:`_detail_1cbba_179`,copyBtn:`_copyBtn_1cbba_203`,daysLeft:`_daysLeft_1cbba_217`,scopes:`_scopes_1cbba_223`,scopeTags:`_scopeTags_1cbba_227`,scopeTag:`_scopeTag_1cbba_227`,keyActions:`_keyActions_1cbba_243`,revokeBtn:`_revokeBtn_1cbba_250`,info:`_info_1cbba_265`},yi=({apiUrl:e,token:t,namespace:n=`app-store-sherpa`,onConfigure:r})=>{let[i,a]=(0,g.useState)([]),[o,s]=(0,g.useState)(!0),[c,l]=(0,g.useState)(null),[u,d]=(0,g.useState)(!1),[f,p]=(0,g.useState)(null),[m,h]=(0,g.useState)(``),[_,v]=(0,g.useState)([`state:read`,`state:write`,`events:read`]),y=[`state:read`,`state:write`,`events:read`,`backup:create`,`backup:restore`,`admin:logs`,`admin:restart`],b=[`state:read`,`state:write`,`events:read`,`backup:create`,`backup:restore`,`admin:logs`,`admin:restart`];(0,g.useEffect)(()=>{x()},[e,t]);let x=async()=>{try{if(s(!0),l(null),!e){l(`A server or managed API URL is not configured.`),s(!1);return}let n=await fetch(`${e}/api/keys`,{headers:t?{Authorization:`Bearer ${t}`}:{},signal:AbortSignal.timeout(1e4)});if(n.status===401)throw Error(`Unauthorized: Invalid or expired API token`);if(n.status===403)throw Error(`Forbidden: Your account does not have permission to manage API keys`);if(!n.ok)throw Error(`Failed to fetch keys: ${n.status} ${n.statusText}`);let r=await n.json();a(r.tokens||[])}catch(t){let n=t instanceof TypeError?`Connection error: Unable to reach ${e}. Is the server running?`:t instanceof Error?t.message:`Failed to fetch keys`;l(n),console.error(`Error fetching API keys:`,t)}finally{s(!1)}},S=async r=>{r.preventDefault();try{let r=await fetch(`${e}/api/keys`,{method:`POST`,headers:{...t?{Authorization:`Bearer ${t}`}:{},"Content-Type":`application/json`},body:JSON.stringify({id:m||`key-${Date.now()}`,namespace:n,scopes:_.length>0?_:b}),signal:AbortSignal.timeout(1e4)});if(r.status===401)throw Error(`Unauthorized: Invalid or expired API token`);if(r.status===409)throw Error(`A key with this name already exists`);if(!r.ok)throw Error(`Failed to create key: ${r.status} ${r.statusText}`);let i=await r.json();ee(i.secret),h(``),v(b),d(!1),await x()}catch(e){let t=e instanceof TypeError?`Connection error: Unable to reach the API server`:e instanceof Error?e.message:`Failed to create key`;l(t),console.error(`Error creating API key:`,e)}},C=async n=>{if(confirm(`Revoke key "${n}"? This cannot be undone.`))try{let r=await fetch(`${e}/api/keys/${n}`,{method:`DELETE`,headers:t?{Authorization:`Bearer ${t}`}:{},signal:AbortSignal.timeout(1e4)});if(r.status===404)throw Error(`Key not found`);if(r.status===401)throw Error(`Unauthorized: Invalid or expired API token`);if(!r.ok)throw Error(`Failed to revoke key: ${r.status} ${r.statusText}`);await x()}catch(e){let t=e instanceof TypeError?`Connection error: Unable to reach the API server`:e instanceof Error?e.message:`Failed to revoke key`;l(t),console.error(`Error revoking API key:`,e)}},w=(e,t)=>{navigator.clipboard.writeText(e),p(t),setTimeout(()=>p(null),2e3)},[T,ee]=(0,g.useState)(null);return o?(0,P.jsx)(`div`,{className:z.panel,children:`Loading keys...`}):(0,P.jsxs)(`div`,{className:z.panel,children:[(0,P.jsxs)(`div`,{className:z.header,children:[(0,P.jsx)(`h2`,{children:`API Key Management`}),(0,P.jsx)(`button`,{className:z.createButton,onClick:()=>d(!u),disabled:!e,children:u?`✕ Cancel`:`+ New Key`})]}),c&&(0,P.jsxs)(`div`,{className:z.error,children:[(0,P.jsxs)(`strong`,{children:[`⚠ `,c]}),(0,P.jsx)(`div`,{style:{fontSize:`12px`,marginTop:`8px`,lineHeight:`1.5`},children:c.includes(`Connection error`)&&(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(`p`,{children:`To use API key management, ensure:`}),(0,P.jsxs)(`ul`,{style:{margin:`4px 0`,paddingLeft:`20px`},children:[(0,P.jsxs)(`li`,{children:[`FeltDB server is running on `,(0,P.jsx)(`code`,{children:e})]}),(0,P.jsx)(`li`,{children:`VITE_FELTDB_URL environment variable is set correctly`}),(0,P.jsx)(`li`,{children:`Your API token has proper scopes`})]}),(0,P.jsx)(`button`,{onClick:()=>x(),style:{marginTop:`8px`,padding:`4px 12px`,fontSize:`12px`,background:`#667eea`,color:`white`,border:`none`,borderRadius:`4px`,cursor:`pointer`},children:`Retry`})]})})]}),!e&&(0,P.jsxs)(`div`,{className:z.error,children:[(0,P.jsx)(`strong`,{children:`Connect Studio to a server or managed runtime before managing keys.`}),r&&(0,P.jsx)(`button`,{onClick:r,children:`Open connection settings`})]}),T&&(0,P.jsxs)(`div`,{className:z.info,children:[(0,P.jsx)(`strong`,{children:`New secret — copy it now; it will not be shown again.`}),(0,P.jsx)(`code`,{children:T}),(0,P.jsx)(`button`,{onClick:()=>w(T,`created`),children:f===`created`?`✓ Copied`:`Copy secret`})]}),u&&(0,P.jsxs)(`form`,{onSubmit:S,className:z.createForm,children:[(0,P.jsxs)(`div`,{className:z.formGroup,children:[(0,P.jsx)(`label`,{children:`Key Name (optional)`}),(0,P.jsx)(`input`,{type:`text`,value:m,onChange:e=>h(e.target.value),placeholder:`e.g., staging-key-001`})]}),(0,P.jsxs)(`div`,{className:z.formGroup,children:[(0,P.jsx)(`label`,{children:`Scopes`}),(0,P.jsx)(`div`,{className:z.scopeList,children:y.map(e=>(0,P.jsxs)(`label`,{className:z.scopeCheckbox,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:_.includes(e),onChange:t=>{t.target.checked?v([..._,e]):v(_.filter(t=>t!==e))}}),e]},e))})]}),(0,P.jsx)(`button`,{type:`submit`,className:z.submitButton,children:`Create Key`})]}),i.length===0?(0,P.jsx)(`div`,{className:z.empty,children:`No API keys configured. Create one to get started.`}):(0,P.jsx)(`div`,{className:z.keysList,children:i.map(e=>(0,P.jsxs)(`div`,{className:z.keyCard,children:[(0,P.jsxs)(`div`,{className:z.keyHeader,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`h3`,{children:e.name||e.id}),(0,P.jsxs)(`p`,{className:z.namespace,children:[`Namespaces: `,e.namespaces.join(`, `)]})]}),(0,P.jsx)(`span`,{className:`${z.status} ${e.revoked?z.expired:z.active}`,children:e.revoked?`Revoked`:`Active`})]}),(0,P.jsx)(`div`,{className:z.keyDetails,children:(0,P.jsxs)(`div`,{className:z.scopes,children:[(0,P.jsx)(`strong`,{children:`Scopes:`}),(0,P.jsx)(`div`,{className:z.scopeTags,children:e.scopes.map(e=>(0,P.jsx)(`span`,{className:z.scopeTag,children:e},e))})]})}),(0,P.jsx)(`div`,{className:z.keyActions,children:(0,P.jsx)(`button`,{className:z.revokeBtn,onClick:()=>C(e.id),disabled:e.revoked,children:`Revoke`})})]},e.id))}),(0,P.jsx)(`div`,{className:z.info,children:(0,P.jsxs)(`p`,{children:[(0,P.jsx)(`strong`,{children:`Security:`}),` Store tokens securely. Never commit to version control. Secrets are shown once. Revoke and replace a key if its secret is lost.`]})})]})};function bi({db:e,remoteUrl:t=``,token:n=``,namespace:r=`default`,deploymentRuntime:i=`browser`,applicationUrl:a=``,onConnect:o}){let[s,c]=(0,g.useState)(null),l=In(e||null,r),u=Ln(e||null,s,r),{diagnostics:d}=Rn(e||null),f=Bn(e||null),[p,m]=(0,g.useState)(),h=i!==`browser`||!!t,_=e=>({pathname:e,search:window.location.search});return(0,g.useEffect)(()=>{let t=!0;return fetch(`/_feltdb/project`,{cache:`no-store`}).then(async e=>{if(!e.ok)throw Error(`No project model endpoint`);let n=await e.json();t&&c(Br(n.source))}).catch(async()=>{let n=e?await e.collection(`_flow_apps`).all():[];t&&n[0]?.spec&&c(n[0].spec)}),()=>{t=!1}},[e]),(0,P.jsx)(Cn,{children:(0,P.jsxs)(`div`,{className:`studio-app`,children:[(0,P.jsxs)(`nav`,{className:`studio-nav`,children:[(0,P.jsxs)(`div`,{className:`nav-header`,children:[(0,P.jsx)(`h1`,{children:`FeltDB Studio`}),l&&(0,P.jsx)(`div`,{className:`instance-info`,children:l.namespace})]}),(0,P.jsx)(`div`,{className:`nav-search`,children:(0,P.jsx)(nr,{db:e,model:s})}),(0,P.jsxs)(`ul`,{className:`nav-menu`,children:[(0,P.jsx)(`li`,{className:`nav-section`,children:`Design`}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/`),children:`Application`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/capabilities`),children:`Capabilities`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/workflows`),children:`Workflows`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/agents`),children:`Agents`})}),(0,P.jsx)(`li`,{className:`nav-section`,children:`Observe`}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/overview`),children:`Overview`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/data`),children:`Data`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/references`),children:`References`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/operations`),children:`Operations`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/executions`),children:`Executions`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/peers`),children:`Peers`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/provenance`),children:`Provenance`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/conflicts`),children:`Conflicts`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/health`),children:`Health`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/settings`),children:`Settings`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/api-keys`),children:`API Keys`})})]})]}),(0,P.jsxs)(`main`,{className:`studio-content`,children:[!h&&(0,P.jsx)(`div`,{className:`runtime-notice`,children:`Browser data is read live from the generated application origin through the local Studio bridge.`}),(0,P.jsxs)(zt,{children:[(0,P.jsx)(j,{path:`/`,element:(0,P.jsx)(vi,{db:e,namespace:r,projectSpec:s,onSpecChange:c})}),(0,P.jsx)(j,{path:`/overview`,element:(0,P.jsx)(Fn,{stats:u})}),(0,P.jsx)(j,{path:`/data`,element:(0,P.jsx)(Hn,{db:e,model:s,namespace:r,applicationUrl:i===`browser`?a:``})}),(0,P.jsx)(j,{path:`/state`,element:(0,P.jsx)(Hn,{db:e,model:s,namespace:r,applicationUrl:i===`browser`?a:``})}),(0,P.jsx)(j,{path:`/references`,element:(0,P.jsx)(Wn,{db:e,model:s,namespace:r})}),(0,P.jsx)(j,{path:`/operations`,element:(0,P.jsx)(Gn,{db:e,model:s,namespace:r})}),(0,P.jsx)(j,{path:`/peers`,element:(0,P.jsx)(Kn,{peers:f,localInstance:l?.instanceId})}),(0,P.jsx)(j,{path:`/capabilities`,element:(0,P.jsx)(qn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/executions`,element:(0,P.jsx)(Yn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/workflows`,element:(0,P.jsx)(Zn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/agents`,element:(0,P.jsx)(Qn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/provenance`,element:(0,P.jsx)($n,{db:e,model:s,namespace:r,reference:p})}),(0,P.jsx)(j,{path:`/conflicts`,element:(0,P.jsx)(Xn,{db:e,diagnostics:d})}),(0,P.jsx)(j,{path:`/health`,element:(0,P.jsx)(er,{diagnostics:d,model:s})}),(0,P.jsx)(j,{path:`/settings`,element:(0,P.jsx)(tr,{db:e,remoteUrl:t,token:n,onConnect:o})}),(0,P.jsx)(j,{path:`/api-keys`,element:(0,P.jsxs)(`div`,{style:{padding:`2rem`},children:[(0,P.jsx)(`h1`,{children:`API Key Management`}),(0,P.jsx)(yi,{apiUrl:t,token:n,namespace:r,onConfigure:()=>window.location.assign(`/settings`)})]})})]})]})]})})}var xi=new URLSearchParams(window.location.search),Si=xi.get(`connect`)||``,Ci=xi.get(`namespace`)||`default`,wi=xi.get(`runtime`)||(Si?`remote`:`browser`),Ti=xi.get(`app`)||``;function Ei(){let[e,t]=(0,g.useState)(Si),[n,r]=(0,g.useState)(()=>Si?window.sessionStorage.getItem(`feltdb-token:${Si}`):``);g.useEffect(()=>{if(!Si||n!==null)return;let e=!0;return fetch(`/_feltdb/config`,{cache:`no-store`}).then(async e=>e.ok?e.json():{}).then(t=>{if(!e)return;let n=t.token||``;n&&window.sessionStorage.setItem(`feltdb-token:${Si}`,n),r(n)}).catch(()=>{e&&r(``)}),()=>{e=!1}},[n]);let i=(0,g.useMemo)(()=>n===null?null:window.feltdb||fi(e?{namespace:Ci,server:{url:e,token:n}}:{namespace:Ci,browser:!0}),[e,n]);return n===null?(0,P.jsx)(`div`,{style:{padding:`2rem`},children:`Connecting Studio…`}):(0,P.jsx)(bi,{db:i||void 0,remoteUrl:e,token:n,namespace:Ci,deploymentRuntime:wi,applicationUrl:Ti,onConnect:(e,n)=>{let i=e.trim().replace(/\/$/,``);i&&n&&window.sessionStorage.setItem(`feltdb-token:${i}`,n),t(i),r(n)}})}_.createRoot(document.getElementById(`root`)).render((0,P.jsx)(g.StrictMode,{children:(0,P.jsx)(Ei,{})}));
|
|
28
|
+
`)}\n}\n`}function Wr(e,t){let n=e=>new Map([...e.collections.map(e=>[`collection ${e.name}`,JSON.stringify(e)]),...e.capabilities.map(e=>[`capability ${e.name}`,JSON.stringify(e)]),...e.agents.map(e=>[`agent ${e.name}`,JSON.stringify(e)]),...e.workflows.map(e=>[`workflow ${e.name}`,JSON.stringify(e)]),...e.triggers.map(e=>[`trigger ${e.event}`,JSON.stringify(e)]),...e.policies.map(e=>[`policy ${e.name}`,JSON.stringify(e)]),...e.schedules.map(e=>[`schedule ${e.name}`,JSON.stringify(e)])]),r=n(e),i=n(t);return{added:[...i.keys()].filter(e=>!r.has(e)),removed:[...r.keys()].filter(e=>!i.has(e)),changed:[...i.keys()].filter(e=>r.has(e)&&r.get(e)!==i.get(e))}}function Gr(e,t){let n=[],r=new Map(e.collections.map(e=>[e.name,e])),i=new Map(t.collections.map(e=>[e.name,e]));for(let[e,t]of i){let i=r.get(e);if(!i){n.push({kind:`add`,target:`collection ${e}`,safety:`safe`,detail:`Create collection model`});continue}let a=new Map(i.fields.map(e=>[e.name,e])),o=new Map(t.fields.map(e=>[e.name,e]));for(let[t,r]of o){let i=a.get(t);i?(i.type!==r.type||i.optional!==r.optional)&&n.push({kind:`change`,target:`${e}.${t}`,safety:`requires_transform`,detail:`${i.type}${i.optional?`?`:``} → ${r.type}${r.optional?`?`:``}`}):n.push({kind:`add`,target:`${e}.${t}`,safety:r.optional?`safe`:`requires_transform`,detail:r.optional?`Add optional field`:`Required field needs a backfill`})}for(let t of a.keys())o.has(t)||n.push({kind:`remove`,target:`${e}.${t}`,safety:`destructive`,detail:`Field is no longer declared`})}for(let e of r.keys())i.has(e)||n.push({kind:`remove`,target:`collection ${e}`,safety:`destructive`,detail:`Collection model is no longer declared`});let a=Wr(e,t);for(let e of a.added.filter(e=>!e.startsWith(`collection `)))n.push({kind:`add`,target:e,safety:`safe`,detail:`Deploy application primitive`});for(let e of a.changed.filter(e=>!e.startsWith(`collection `)))n.push({kind:`change`,target:e,safety:`safe`,detail:`Version application primitive`});for(let e of a.removed.filter(e=>!e.startsWith(`collection `)))n.push({kind:`remove`,target:e,safety:`destructive`,detail:`Application primitive is no longer declared`});return n}function Kr(e=`MyApp`){return{version:1,app:e,collections:[],capabilities:[],agents:[],workflows:[],triggers:[],policies:[],schedules:[]}}var qr=class{constructor(e=`offline`){this.value=e,this.listeners=new Set}subscribe(e){return this.listeners.add(e),e(this.value),()=>this.listeners.delete(e)}set(e){this.value=e;for(let t of this.listeners)t(e)}get(){return this.value}},Jr=class{constructor(e){this.config=e,this.status=new qr,this.fetcher=e.fetcher||fetch,this.restore()}key(){return`feltdb:sync:v1:${this.config.device.application_id}:${this.config.device.device_id}`}restore(){if(!(typeof localStorage>`u`))try{let e=JSON.parse(localStorage.getItem(this.key())||`{}`);this.sessionId=e.sessionId,this.cursor=e.cursor,this.error=e.error}catch{}}persist(){typeof localStorage<`u`&&localStorage.setItem(this.key(),JSON.stringify({sessionId:this.sessionId,cursor:this.cursor,error:this.error,outbox:this.readOutbox()}))}readOutbox(){if(typeof localStorage>`u`)return[];try{return JSON.parse(localStorage.getItem(`${this.key()}:outbox`)||`[]`)}catch{return[]}}writeOutbox(e){typeof localStorage<`u`&&localStorage.setItem(`${this.key()}:outbox`,JSON.stringify(e))}async request(e,t){let n=await this.fetcher(`${this.config.endpoint||``}/v1/sync/${e}`,{method:`POST`,credentials:`include`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json().catch(()=>({}));if(!n.ok)throw Error(r.error||`sync ${e} failed (${n.status})`);return r}async start(){this.status.set(`connecting`);try{if(!this.sessionId){let e={resources:this.config.scope.resources||this.config.scope.collections?.map(e=>`flow://${this.config.device.application_id}/${e}/*`)||[],fields:this.config.scope.fields||{}},t=await this.request(`session`,{device:{...this.config.device,created_at:Math.floor(Date.now()/1e3)},scope:e,offline_grant:this.config.offlineGrant});this.sessionId=t.session_id,this.cursor=t.cursor,this.persist()}return await this.flush(),this.timer=setInterval(()=>void this.flush(),5e3),this}catch(e){throw this.error=String(e),this.status.set(`degraded`),this.persist(),e}}async stop(){this.timer&&clearInterval(this.timer),this.sessionId&&await this.request(`close`,{session_id:this.sessionId}),this.status.set(`offline`)}enqueue(e){let t=this.readOutbox();return t.some(t=>t.operation_id===e.operation_id)||(t.push(e),this.writeOutbox(t)),e.operation_id}async flush(){if(!(!this.sessionId||!this.cursor)){this.status.set(`syncing`);try{let e=this.readOutbox();if(e.length){let t=await this.request(`push`,{session_id:this.sessionId,operations:e}),n=new Set([...t.acknowledgements.map(e=>e.operation_id),...t.rejections.filter(e=>!e.retryable).map(e=>e.operation_id)]);this.writeOutbox(e.filter(e=>!n.has(e.operation_id))),this.cursor=t.cursor}let t=await this.request(`pull`,{session_id:this.sessionId,cursor:this.cursor,limit:250});this.cursor=t.cursor,await this.request(`ack`,{session_id:this.sessionId,cursor:this.cursor}),this.error=void 0,this.status.set(`synced`),this.persist()}catch(e){this.error=String(e),this.status.set(typeof navigator<`u`&&!navigator.onLine?`offline`:`degraded`),this.persist()}}}pending(){return this.readOutbox()}conflicts(){return this.readOutbox().filter(e=>e.status===`CONFLICTED`)}lastCursor(){return this.cursor}lastError(){return this.error}},Yr=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`,...t?.headers||{}},...t}),r=n.status===204?void 0:await n.json();if(!n.ok)throw Error(r?.error||`Workload request failed (${n.status})`);return r}create(e){return this.json(`/v1/workloads`,{method:`POST`,body:JSON.stringify({...e,created_at:e.created_at||Math.floor(Date.now()/1e3)})})}list(e){return this.json(`/v1/workloads?application_id=${encodeURIComponent(e)}`)}inspect(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}`)}claim(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/claim`,{method:`POST`,body:JSON.stringify(t)})}start(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/start`,{method:`POST`,body:JSON.stringify(t)})}heartbeat(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/heartbeat`,{method:`POST`,body:JSON.stringify(t)})}checkpoint(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/checkpoint`,{method:`POST`,body:JSON.stringify(t)})}complete(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/complete`,{method:`POST`,body:JSON.stringify(t)})}fail(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/fail`,{method:`POST`,body:JSON.stringify(t)})}confirmCancelled(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/cancelled`,{method:`POST`,body:JSON.stringify(t)})}executionContext(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/context`,{method:`POST`,body:JSON.stringify(t)})}cancel(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/cancel`,{method:`POST`,body:JSON.stringify({grant:t})})}retry(e,t){return this.json(`/v1/workloads/${encodeURIComponent(e)}/retry`,{method:`POST`,body:JSON.stringify({grant:t})})}history(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}/history`)}result(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}/result`)}},Xr=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`,...t?.headers||{}},...t}),r=n.status===204?void 0:await n.json();if(!n.ok)throw Error(r?.error||`Mesh request failed (${n.status})`);return r}},Zr=class extends Xr{register(e){return this.json(`/v1/workers/register`,{method:`POST`,body:JSON.stringify({...e,registered_at:e.registered_at||Math.floor(Date.now()/1e3)})})}list(e){return this.json(`/v1/workers?application_id=${encodeURIComponent(e)}`)}inspect(e){return this.json(`/v1/workers/${encodeURIComponent(e)}`)}heartbeat(e,t,n){return this.json(`/v1/workers/${encodeURIComponent(e)}/heartbeat`,{method:`POST`,body:JSON.stringify({heartbeat:t,grant:n})})}drain(e,t){return this.json(`/v1/workers/${encodeURIComponent(e)}/drain`,{method:`POST`,body:JSON.stringify({grant:t})})}recover(e,t){return this.json(`/v1/workers/${encodeURIComponent(e)}/recover`,{method:`POST`,body:JSON.stringify({grant:t})})}reconcile(e,t,n){return this.json(`/v1/workers/${encodeURIComponent(e)}/reconcile`,{method:`POST`,body:JSON.stringify({reconciliation:t,grant:n})})}},Qr=class extends Xr{list(e){return this.json(`/v1/worker-pools?application_id=${encodeURIComponent(e)}`)}create(e,t){return this.json(`/v1/worker-pools`,{method:`POST`,body:JSON.stringify({pool:e,grant:t})})}inspect(e){return this.json(`/v1/worker-pools/${encodeURIComponent(e)}`)}},$r=class extends Xr{async status(e){let[t,n]=await Promise.all([new Zr(this.baseUrl,this.fetcher).list(e),new Qr(this.baseUrl,this.fetcher).list(e)]);return{workers:t.workers,pools:n.pools,ready:t.workers.filter(e=>e.lifecycle===`READY`).length,busy:t.workers.filter(e=>e.lifecycle===`BUSY`).length}}eligibleWorkers(e){return this.json(`/v1/workloads/${encodeURIComponent(e)}/eligible-workers`)}},ei=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Artifact request failed (${n.status})`);return r}async create(e){let t=new URLSearchParams({application_id:e.applicationId,kind:typeof e.kind==`string`?e.kind:`OTHER(${e.kind.OTHER})`,name:e.name,content_type:e.contentType,producer_kind:e.producerKind||`human`,producer_id:e.producerId||``});for(let n of e.parents||[])t.append(`parents`,n);for(let[n,r]of Object.entries({supersedes:e.supersedes,revision:e.revision,workload:e.workload,execution:e.execution}))r&&t.set(n,r);return this.json(`/v1/artifacts?${t}`,{method:`POST`,headers:{"content-type":e.contentType},body:(e.content instanceof Blob||e.content instanceof Uint8Array,e.content)})}list(e){return this.json(`/v1/artifacts?application_id=${encodeURIComponent(e)}`)}get(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}`)}async content(e){let t=await this.fetcher(`${this.baseUrl}/v1/artifacts/${encodeURIComponent(e)}/content`,{credentials:`include`});if(!t.ok)throw Error(`Artifact content failed (${t.status})`);return new Uint8Array(await t.arrayBuffer())}provenance(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/provenance`)}parents(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/parents`)}children(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/children`)}archive(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/archive`,{method:`POST`})}restore(e){return this.json(`/v1/artifacts/${encodeURIComponent(e)}/restore`,{method:`POST`})}},ti=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Bundle request failed (${n.status})`);return r}export(e,t={}){return this.json(`/v1/bundles/export`,{method:`POST`,body:JSON.stringify({application_id:e,options:t})})}inspect(e){return this.json(`/v1/bundles/${encodeURIComponent(e)}`)}verify(e){return this.json(`/v1/bundles/${encodeURIComponent(e)}/verify`,{method:`POST`})}planImport(e,t,n,r){return this.json(`/v1/bundles/import/plan`,{method:`POST`,body:JSON.stringify({bundle:e,mode:t,destination_tenant:n,destination_application:r})})}import(e,t,n,r){return this.json(`/v1/bundles/import/apply`,{method:`POST`,body:JSON.stringify({bundle:e,mode:t,destination_tenant:n,destination_application:r})})}},ni=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Release request failed (${n.status})`);return r}create(e){return this.json(`/v1/releases`,{method:`POST`,body:JSON.stringify({manifest:e})})}list(e){return this.json(`/v1/releases?application_id=${encodeURIComponent(e)}`)}get(e){return this.json(`/v1/releases/${encodeURIComponent(e)}`)}verify(e){return this.json(`/v1/releases/${encodeURIComponent(e)}/verify`,{method:`POST`})}promote(e,t,n){return this.json(`/v1/releases/${encodeURIComponent(e)}/promote`,{method:`POST`,body:JSON.stringify({application_id:t,environment:n})})}plan(e,t,n){return this.json(`/v1/deployments/plan`,{method:`POST`,body:JSON.stringify({release_id:e,environment:t,rollback_target:n})})}deploy(e){return this.json(`/v1/deployments`,{method:`POST`,body:JSON.stringify({plan:e})})}status(e){return this.json(`/v1/deployments/${encodeURIComponent(e)}`)}health(e){return this.json(`/v1/deployments/${encodeURIComponent(e)}/health`)}stop(e){return this.json(`/v1/deployments/${encodeURIComponent(e)}/stop`,{method:`POST`})}},ri=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Observe request failed (${n.status})`);return r}events(e){return this.json(`/v1/observability/events?application_id=${encodeURIComponent(e)}`)}cause(e){return this.json(`/v1/observability/causes/${encodeURIComponent(e)}`)}workload(e){return this.json(`/v1/observability/workloads/${encodeURIComponent(e)}/timeline`)}execution(e){return this.json(`/v1/observability/executions/${encodeURIComponent(e)}/timeline`)}revision(e){return this.json(`/v1/observability/revisions/${encodeURIComponent(e)}/timeline`)}append(e){return this.json(`/v1/observability/events`,{method:`POST`,body:JSON.stringify({event:e})})}},ii=class{constructor(e=``,t=fetch){this.baseUrl=e,this.fetcher=t}async json(e,t){let n=await this.fetcher(`${this.baseUrl}${e}`,{credentials:`include`,headers:{"content-type":`application/json`},...t}),r=await n.json();if(!n.ok)throw Error(r?.error||`Provider request failed (${n.status})`);return r}list(){return this.json(`/v1/providers`)}inspect(e){return this.json(`/v1/providers/${encodeURIComponent(e)}`)}install(e,t,n){return this.json(`/v1/providers`,{method:`POST`,body:JSON.stringify({manifest:e,tenant_id:t,application_id:n})})}enable(e){return this.status(e,`ENABLED`)}disable(e){return this.status(e,`DISABLED`)}revoke(e){return this.status(e,`REVOKED`)}status(e,t){return this.json(`/v1/providers/${encodeURIComponent(e)}/status`,{method:`POST`,body:JSON.stringify({status:t})})}health(e){return this.json(`/v1/providers/${encodeURIComponent(e)}/health`)}dependencies(e){return this.json(`/v1/providers/${encodeURIComponent(e)}/dependencies`)}},ai=()=>typeof window<`u`&&window.document!==void 0,oi=e=>typeof process<`u`?{}[e]:void 0,si=()=>{let e=globalThis.crypto;if(typeof e?.randomUUID==`function`)return e.randomUUID();let t=new Uint8Array(16);if(typeof e?.getRandomValues==`function`)e.getRandomValues(t);else for(let e=0;e<t.length;e+=1)t[e]=Math.floor(Math.random()*256);t[6]=t[6]&15|64,t[8]=t[8]&63|128;let n=Array.from(t,e=>e.toString(16).padStart(2,`0`)).join(``);return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`},ci=class{constructor(){this.id=null,this.identityFile=null}getId(){if(this.id)return this.id;try{if(ai()){let e=globalThis.localStorage?.getItem(`feltdb.install-id`);return this.id=e&&this.isValidUUID(e)?e:si(),globalThis.localStorage?.setItem(`feltdb.install-id`,this.id),this.id}return this.id=si(),this.id}catch{return this.id||=si(),this.id}}isValidUUID(e){return/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e)}},li=class{constructor(e=`0.5.7`){this.batchSize=10,this.eventQueue=[],this.flushTimer=null,this.runtime=`node`,this.coreVersion=e,this.identity=new ci,this.enabled=oi(`FELTDB_TELEMETRY`)!==`0`&&oi(`FELTDB_TELEMETRY`)!==`false`,ai()&&(this.runtime=`browser`)}emit(e){if(this.enabled)try{let t={event:e,installation_id:this.identity.getId(),core_version:this.coreVersion,runtime:this.runtime,os:this.getOS(),timestamp:new Date().toISOString()};this.eventQueue.push(t),this.eventQueue.length>=this.batchSize?this.flush():this.scheduleFlush()}catch{}}async flush(){if(this.eventQueue.length===0||!this.enabled)return;this.flushTimer&&=(clearTimeout(this.flushTimer),null);let e=this.eventQueue.splice(0,this.batchSize);try{await this.sendEvents(e)}catch{}}scheduleFlush(){this.flushTimer||!this.enabled||(this.flushTimer=setTimeout(()=>{this.flush().catch(()=>{})},5e3))}async sendEvents(e){let t=oi(`FELTDB_TELEMETRY_ENDPOINT`)||`https://feltdb.com/api/v1/telemetry/events`,n=new AbortController,r=setTimeout(()=>n.abort(),3e3);try{(await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({events:e}),signal:n.signal})).ok}catch{}finally{clearTimeout(r)}}getOS(){if(ai())return`browser`;let e=typeof process<`u`?process.platform:`unknown`;switch(e){case`darwin`:return`macos`;case`linux`:return`linux`;case`win32`:return`windows`;case`freebsd`:return`freebsd`;default:return e}}enable(){this.enabled=!0}disable(){this.enabled=!1,this.eventQueue=[],this.flushTimer&&=(clearTimeout(this.flushTimer),null)}isEnabled(){return this.enabled}async forceFlush(){for(;this.eventQueue.length>0;)await this.flush()}},ui=null;function R(e){return ui||=new li(e),ui}function di(e){R().emit(e)}function fi(e){if(!e?.namespace?.trim())throw Error(`createFeltDB requires a non-empty namespace`);return new pi(e.server?new I(e.server):`browser`in e&&e.browser?new wr(e.namespace):`path`in e&&e.path?new Fr(e.path):new Cr(e.namespace))}var pi=class{constructor(e){this.collections=new Map,this.cells=new Map,this.capabilityWorkers=new Map,this.workloads=new Yr,this.artifacts=new ei,this.bundle=new ti,this.releases=new ni,this.observe=new ri,this.providers=new ii,this.workers=new Zr,this.workerPools=new Qr,this.mesh=new $r,this.jsDb=e,this.runtimeInfo=this.detectRuntime(),this.agentRegistry=new yr;let t={persistent:this.runtimeInfo.persistent,executionTimeoutMs:3e4,supportsReactiveTriggers:!0,defaultRetryPolicy:{maxAttempts:3,backoffMs:1e3}};this.agentRuntime=new xr(this.agentRegistry,t),di(`initialize`)}detectRuntime(){let e=typeof window<`u`&&typeof document<`u`,t=typeof globalThis<`u`&&`versions`in globalThis&&`node`in globalThis.versions,n=this.jsDb instanceof Cr,r=this.jsDb instanceof I,i=this.jsDb instanceof wr,a=`memory`,o=!1;return r?(a=`remote`,o=!0):n?a=`memory`:i?(a=`indexeddb`,o=!0):t&&(a=`file`,o=!0),{runtime:r?`remote`:i||e?`browser`:t?`node`:`wasm`,storage:a,persistent:o,reactive:!0,durable:o,version:`0.1.0`,supportsCheckpointing:o,supportsLifecycle:e||i}}runtime(){return{...this.runtimeInfo}}collection(e){return this.collections.has(e)||this.collections.set(e,new mr(this.jsDb,e)),this.collections.get(e)}cell(e){return this.cells.has(e)||this.cells.set(e,new gr(this.jsDb,e)),this.cells.get(e)}async acquire(e,t){return this.jsDb instanceof I?this.jsDb.acquire(e,t):this.collection(e).get(t)}async search(e,t,n=50){if(this.jsDb instanceof I)return this.jsDb.search(e,t,n);let r=t.toLowerCase();return(await this.collection(e).all()).filter(e=>JSON.stringify(e).toLowerCase().includes(r)).slice(0,n)}async defineCapability(e,t){if(!(this.jsDb instanceof I))throw Error(`Distributed capabilities require a server runtime`);return this.jsDb.command(`/capabilities/${encodeURIComponent(e)}`,{steps:t})}registerCapabilityWorker(e,t){if(this.jsDb instanceof I)throw Error(`Remote capability workers are installed on the server`);return this.capabilityWorkers.set(e,t),()=>this.capabilityWorkers.delete(e)}async executeCapability(e,t){if(this.jsDb instanceof I)return this.jsDb.command(`/capabilities/${encodeURIComponent(e)}/execute`,t);let n=this.capabilityWorkers.get(e);if(!n)throw Error(`No embedded capability worker registered for ${e}`);let r=`cap-${e}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,i=this.collection(`_flow_executions`);await i.insert({id:r,capability:e,input:t,status:`running`,owner:this.instanceId(),started_at:Date.now()},r);try{let e=await n(t);return await i.update(r,{status:`completed`,output:e,completed_at:Date.now()}),e}catch(e){throw await i.update(r,{status:`failed`,error:e instanceof Error?e.message:String(e),completed_at:Date.now()}),e}}async changeClusterMembership(e,t){if(!(this.jsDb instanceof I))throw Error(`Cluster membership requires a server runtime`);return this.jsDb.command(`/cluster/members`,{expected_epoch:e,peers:t})}async deployFlowSpec(e,t,n=!1){let r=Vr(e).filter(e=>e.severity===`error`);if(r.length)throw Error(r.map(e=>e.message).join(`; `));let i=this.collection(`_flow_apps`),a=await i.get(e.app),o=(a?.version??0)+1;if(t!==void 0&&(a?.version??0)!==t)throw Error(`FlowSpec version conflict: expected ${t}, found ${a?.version??0}`);let s=Gr(a?.spec??Kr(e.app),e),c=s.filter(e=>e.safety===`destructive`);if(c.length&&!n)throw Error(`Destructive migration requires explicit approval: ${c.map(e=>e.target).join(`, `)}`);let l={id:e.app,app:e.app,version:o,status:`deploying`,spec:e,migration:s,deployed_at:Date.now()};a?await i.update(e.app,l):await i.insert(l,e.app);let u=(t,n)=>`${e.app}-${t}-${n}`.replace(/[^A-Za-z0-9_-]/g,`_`),d=async(t,n,r,i)=>{let a=this.collection(t),s=new Set(i.map(e=>e.name??e.event??`unnamed`));for(let e of r){let t=e.name??e.event??`unnamed`;s.has(t)||await a.delete(u(n,t))}for(let t of i){let r=t.name??t.event??`unnamed`,i=u(n,r),s={id:i,app:e.app,version:o,...t};await a.get(i)?await a.update(i,s):await a.insert(s,i)}},f=a?.spec??Kr(e.app);if(await d(`_flow_collection_models`,`collection`,f.collections,e.collections),await d(`_flow_capability_models`,`capability`,f.capabilities,e.capabilities),await d(`_flow_trigger_models`,`trigger`,f.triggers,e.triggers),await d(`_flow_policy_models`,`policy`,f.policies,e.policies),await d(`_flow_schedule_models`,`schedule`,f.schedules,e.schedules),this.jsDb instanceof I){for(let t of f.workflows)e.workflows.some(e=>e.name===t.name)||await this.collection(`_flow_workflows`).delete(u(`workflow`,t.name));for(let t of f.agents)e.agents.some(e=>e.name===t.name)||await this.collection(`_flow_agents`).delete(u(`agent`,t.name));for(let t of e.workflows)await this.defineWorkflow(u(`workflow`,t.name),t.steps.map(e=>e.name));for(let t of e.agents){let n=t.statements.filter(e=>e.startsWith(`capability `)).map(e=>e.slice(11).trim());await this.defineStateAgent(u(`agent`,t.name),n,{flowspec_app:e.app,flowspec_version:o})}}else await d(`_flow_workflows`,`workflow`,f.workflows,e.workflows),await d(`_flow_agents`,`agent`,f.agents,e.agents);let p={...l,status:`active`};return await i.update(e.app,p),await this.collection(`_flow_app_versions`).insert({id:`${e.app}-${o}`,app:e.app,version:o,spec:e,migration:s,deployed_at:p.deployed_at},`${e.app}-${o}`),{app:e.app,version:o,status:`active`}}async auditEvents(){return this.jsDb.audit_events?await this.jsDb.audit_events():[]}async exportOperations(e=0){if(!this.jsDb.export_operations)throw Error(`This runtime uses server-managed replication`);return await this.jsDb.export_operations(e)}async applyOperations(e){if(!this.jsDb.apply_remote_operations)throw Error(`This runtime uses server-managed replication`);return await this.jsDb.apply_remote_operations(e)}async synchronizeWith(e){let t=await this.exportOperations(),n=await e.exportOperations();await this.addSyncPeer(e.instanceId()),await e.addSyncPeer(this.instanceId());let r=await e.applyOperations(t),i=await this.applyOperations(n);return{sent:t.length,received:n.length,applied:i.applied+r.applied,ignored:i.ignored+r.ignored}}async executeCapabilityWithFailover(e,t,n=[]){let r=this.collection(`_flow_capability_routes`),i=`route-${e}-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,a=[this,...n],o=[];await r.insert({id:i,capability:e,status:`routing`,input:t,candidates:a.map(e=>e.instanceId()),started_at:Date.now()},i);for(let n of a)try{let a=await n.executeCapability(e,t);return await r.update(i,{status:`completed`,provider:n.instanceId(),attempts:o.length+1,failures:o,completed_at:Date.now()}),{output:a,provider:n.instanceId(),attempts:o.length+1}}catch(e){o.push({provider:n.instanceId(),error:e instanceof Error?e.message:String(e)})}throw await r.update(i,{status:`failed`,attempts:o.length,failures:o,completed_at:Date.now()}),Error(`No provider could execute capability ${e}: ${o.map(e=>e.error).join(`; `)}`)}async recordProvenance(e,t){if(!(this.jsDb instanceof I))throw Error(`Causal provenance requires a server runtime`);return this.jsDb.provenance(e,t)}async storeContent(e){if(!(this.jsDb instanceof I))throw Error(`Durable content storage requires a server runtime`);return this.jsDb.storeContent(e)}async acquireContent(e){if(!(this.jsDb instanceof I))throw Error(`Network content acquisition requires a server runtime`);return this.jsDb.acquireContent(e)}async defineWorkflow(e,t){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflows/${encodeURIComponent(e)}`,{steps:t})}async startWorkflow(e,t=null){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflows/${encodeURIComponent(e)}/runs`,{input:t})}async claimWorkflowStep(e,t,n,r=3e4){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflow-runs/${encodeURIComponent(e)}/steps/${encodeURIComponent(t)}/claim`,{worker:n,lease_ms:r})}async completeWorkflowStep(e,t,n,r=null){if(!(this.jsDb instanceof I))throw Error(`Durable workflow coordination requires a server runtime`);return this.jsDb.command(`/workflow-runs/${encodeURIComponent(e)}/steps/${encodeURIComponent(t)}/complete`,{claim_id:n,result:r})}async defineStateAgent(e,t=[],n=null){if(!(this.jsDb instanceof I))throw Error(`Durable agent coordination requires a server runtime`);return this.jsDb.command(`/agents/${encodeURIComponent(e)}`,{capabilities:t,constraints:n})}async startStateAgent(e,t,n=null){if(!(this.jsDb instanceof I))throw Error(`Durable agent coordination requires a server runtime`);return this.jsDb.command(`/agents/${encodeURIComponent(e)}/runs`,{goal:t,input:n})}defineAgent(e){let t=_r(e.name,e.version);return this.agentRegistry.register(t,e),t}agent(e){return this.agentRegistry.getByName(e)?.agentRef}getAgentRegistry(){return this.agentRegistry}getAgentRuntime(){return this.agentRuntime}async createAgentExecution(e,t,n){let r=await this.agentRuntime.createExecution(this,e,t,n);return await this.collection(`_flow_agent_executions`).insert(this.agentExecutionRecord(r),r.executionId),r}agentExecutionRecord(e){return{...e,id:e.executionId,agentRef:e.agentRef.toString()}}async startAgentExecution(e,t=this.instanceId()){await this.agentRuntime.start(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async transitionAgentExecution(e,t){await this.agentRuntime.transition(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async completeAgentExecution(e,t){await this.agentRuntime.complete(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async failAgentExecution(e,t){await this.agentRuntime.fail(e,t),await this.collection(`_flow_agent_executions`).update(e.executionId,this.agentExecutionRecord(e))}async close(){for(let e of this.collections.values())e.close();this.collections.clear(),await this.jsDb.close?.()}sync(e){if(e)return new Jr(e);let t=this.jsDb.sync_info();if(!t.success||!t.data)throw Error(t.error||`Failed to get sync info`);return JSON.parse(t.data)}async addSyncPeer(e){let t=this.jsDb.add_sync_peer(e);if(!t.success)throw Error(t.error||`Failed to add peer`)}async removeSyncPeer(e){let t=this.jsDb.remove_sync_peer(e);if(!t.success)throw Error(t.error||`Failed to remove peer`)}async getPendingForPeer(e,t){let n=this.jsDb.get_pending_for_peer(e,t);if(!n.success||!n.data)throw Error(n.error||`Failed to get pending operations`);return JSON.parse(n.data)}async acknowledgePeerOperations(e,t){let n=this.jsDb.acknowledge_peer_operations(e,t);if(!n.success)throw Error(n.error||`Failed to acknowledge operations`)}instanceId(){return this.jsDb.instance_id()}getSequence(){return this.jsDb.get_sequence()}async registerTrigger(e){}async scheduleCron(e){}async getPendingExecutions(){return[]}async completeExecution(e,t){}provenance(e){let[t,...n]=e.split(`://`)[1]?.split(`/`)||[],r={id:e,type:`Record`,label:n.join(`/`)||e,created_ms:Date.now()};return{root:r,nodes:[r],edges:[]}}health(){let e=this.sync(),t=this.runtime(),n=e.is_connected&&e.pending_operations===0?`healthy`:`degraded`,r=[];e.pending_operations>0&&r.push({severity:`info`,component:`sync`,message:`${e.pending_operations} pending operations`}),e.is_connected||r.push({severity:`warning`,component:`sync`,message:`Network disconnected`}),e.conflicts_detected>0&&r.push({severity:`warning`,component:`sync`,message:`${e.conflicts_detected} conflicts detected`});let i=r.length>0?`degraded`:`healthy`;return{runtime:{status:`healthy`,wasm:t.runtime===`wasm`||t.runtime===`browser`,reactive:t.reactive},storage:{status:`healthy`,backend:t.storage,persistent:t.persistent,durable:t.durable},sync:{status:n,connected:e.is_connected,peers:e.connected_peers.length,pendingOperations:e.pending_operations},fabric:{status:`healthy`,references:0,peers:e.connected_peers.length},capabilities:{status:`healthy`,count:0,available:0},execution:{status:`healthy`,pending:0,running:0,failed:0},workflow:{status:`healthy`,total:0,active:0},status:i,issues:r}}async allocateSequence(e){if(typeof this.jsDb.allocateSequence!=`function`)throw Error(`allocateSequence is not supported by ${this.runtimeInfo.storage} backend. Only FileJsDb (Node.js) supports atomic sequence allocation.`);return this.jsDb.allocateSequence(e)}async putIfAbsent(e,t){if(typeof this.jsDb.putIfAbsent!=`function`)throw Error(`putIfAbsent is not supported by ${this.runtimeInfo.storage} backend. Only FileJsDb (Node.js) supports durable idempotent mutation.`);return this.jsDb.putIfAbsent(e,t)}async cas(e){if(typeof this.jsDb.cas!=`function`)throw Error(`cas is not supported by ${this.runtimeInfo.storage} backend. Only FileJsDb (Node.js) supports compare-and-set with version detection.`);return this.jsDb.cas(e)}},mi;(function(e){e.Insert=`Insert`,e.Update=`Update`,e.Delete=`Delete`,e.Query=`Query`,e.Upsert=`Upsert`})(mi||={});var hi;(function(e){e.Pending=`Pending`,e.Running=`Running`,e.Succeeded=`Succeeded`,e.Failed=`Failed`,e.RetryScheduled=`RetryScheduled`,e.DeadLettered=`DeadLettered`})(hi||={});var gi;(function(e){e.OK=`OK`,e.CONFLICT=`CONFLICT`,e.PRECONDITION_FAILED=`PRECONDITION_FAILED`,e.TOO_BUSY=`TOO_BUSY`,e.INTERNAL_ERROR=`INTERNAL_ERROR`})(gi||={});var _i=Ur(Kr(`Application`));function vi({db:e,namespace:t=`default`,projectSpec:n,onSpecChange:r}){let i=`feltdb:studio:draft:${t}`,a=(0,g.useRef)((()=>{if(typeof window>`u`)return _i;let e=window.localStorage.getItem(i);if(!e)return _i;try{return Br(e),e}catch{return _i}})()),o=(0,g.useRef)(a.current!==_i),[s,c]=(0,g.useState)(a.current),[l,u]=(0,g.useState)(()=>Br(a.current)),[d,f]=(0,g.useState)([]),[p,m]=(0,g.useState)([]),[h,_]=(0,g.useState)(`Draft is valid`),[v,y]=(0,g.useState)(0),[b,x]=(0,g.useState)(null),[S,C]=(0,g.useState)(null),[w,T]=(0,g.useState)(!1),[ee,te]=(0,g.useState)(!1),[E,D]=(0,g.useState)({url:``,namespace:t,token:``,allowDestructive:!1}),ne=(0,g.useRef)(null),re=p.length?p[p.length-1].source:Ur(Kr(l.app)),ie=(0,g.useMemo)(()=>Wr(Br(re),l),[re,l]),ae=(0,g.useMemo)(()=>Gr(Br(re),l),[re,l]);(0,g.useEffect)(()=>{if(!e||n)return;let t=!1;return(async()=>{try{let n=await e.collection(`_flow_apps`).all(),r=n.find(e=>e.status===`active`)??n[0];if(!r||t)return;let i=Ur(r.spec);o.current||(u(r.spec),c(i)),y(r.version??0);let a=(await e.collection(`_flow_app_versions`).all()).filter(e=>e.app===r.app).sort((e,t)=>e.version-t.version);t||(m(a.map(e=>({version:e.version,source:Ur(e.spec),savedAt:e.deployed_at}))),_(`Loaded ${r.app} v${r.version}`))}catch(e){t||_(`Could not load deployed model: ${e instanceof Error?e.message:String(e)}`)}})(),()=>{t=!0}},[e,n]),(0,g.useEffect)(()=>{let e=window.setTimeout(()=>window.localStorage.setItem(i,s),200);return()=>window.clearTimeout(e)},[i,s]);let O=e=>{c(e);try{let t=Br(e),n=Vr(t);u(t),r?.(t),f(n),_(n.some(e=>e.severity===`error`)?`Model has validation errors`:`Draft is valid`)}catch(e){f([{severity:`error`,message:e instanceof Error?e.message:String(e)}]),_(`DSL parse failed`)}};(0,g.useEffect)(()=>{if(!n)return;let e=Ur(n);c(e),u(n),f(Vr(n)),_(`Loaded ${n.app} project model`)},[n]);let oe=e=>{u(e),O(Ur(e))},se=()=>{if(!S)return C({name:``});let e=S.name.trim();if(!/^[A-Z][A-Za-z0-9_]*$/.test(e))return C({...S,error:`Use a capitalized name with no spaces.`});if(l.collections.some(t=>t.name===e))return C({...S,error:`That collection already exists.`});oe({...l,collections:[...l.collections,{name:e,fields:[],indexes:[]}]}),C(null)},ce=e=>x({collection:e,name:``,type:`text`,reference:``,optional:!1}),le=()=>{if(!b)return;let e=b.name.trim(),t=l.collections.find(e=>e.name===b.collection);if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e))return x({...b,error:`Use a letter-led name with no spaces.`});if(t?.fields.some(t=>t.name===e))return x({...b,error:`That field already exists.`});if([`ref`,`enum`,`array`,`map`,`vector`].includes(b.type)&&!b.reference.trim())return x({...b,error:`Configure this field type.`});let n=b.type===`ref`?`ref ${b.reference}`:b.type===`enum`?`enum(${b.reference.split(`,`).map(e=>e.trim()).filter(Boolean).join(`,`)})`:b.type===`array`?`array<${b.reference.trim()}>`:b.type===`map`?`map<${b.reference.trim()}>`:b.type===`vector`?`vector<${b.reference.trim()}>`:b.type;oe({...l,collections:l.collections.map(t=>t.name===b.collection?{...t,fields:[...t.fields,{name:e,type:n,optional:b.optional}]}:t)}),x(null)},k=()=>{let e=[...p,{version:p.length+1,source:s,savedAt:Date.now()}];m(e),_(`Saved local revision v${e.length}`)},ue=async()=>{if(!e)return _(`Local embedded storage is unavailable`);if(d.some(e=>e.severity===`error`))return _(`Resolve validation errors before deploying`);if(ae.filter(e=>e.safety===`destructive`).length&&!w)return _(`Review and approve destructive local changes before applying`);try{let t=await e.deployFlowSpec(l,v,w),n=[...p,{version:t.version,source:s,savedAt:Date.now()}];m(n),y(t.version),T(!1),_(`Applied locally as ${t.app} v${t.version}`)}catch(e){_(`Local apply failed: ${e instanceof Error?e.message:String(e)}`)}},de=async()=>{if(!E.url.trim()||!E.token.trim())return D({...E,error:`Cloud URL and API key are required.`});if(d.some(e=>e.severity===`error`))return D({...E,error:`Resolve validation errors before publishing.`});D({...E,publishing:!0,error:void 0});let e=fi({namespace:E.namespace.trim()||t,server:{url:E.url.trim().replace(/\/$/,``),token:E.token}});try{let t=await e.collection(`_flow_apps`).get(l.app),n=Gr(t?.spec??Kr(l.app),l).filter(e=>e.safety===`destructive`);if(n.length&&!E.allowDestructive)return D({...E,publishing:!1,destructive:n.map(e=>e.target),error:`Review and approve destructive changes: ${n.map(e=>e.target).join(`, `)}`});let r=await e.deployFlowSpec(l,t?.version??0,E.allowDestructive);window.sessionStorage.setItem(`feltdb-token:${E.url.trim()}`,E.token),D({...E,publishing:!1,token:``,error:void 0}),te(!1),_(`Published ${r.app} v${r.version} to cloud`)}catch(e){D({...E,publishing:!1,error:e instanceof Error?e.message:String(e)})}finally{await e.close()}},fe=()=>{let e=URL.createObjectURL(new Blob([s],{type:`text/plain`})),t=document.createElement(`a`);t.href=e,t.download=`feltdb.flow`,t.click(),URL.revokeObjectURL(e)},pe=async e=>{e&&O(await e.text())},me=[[`Data`,l.collections.map(e=>e.name)],[`Capabilities`,l.capabilities.map(e=>e.name)],[`Agents`,l.agents.map(e=>e.name)],[`Workflows`,l.workflows.map(e=>e.name)],[`Triggers`,l.triggers.map(e=>e.event)],[`Policies`,l.policies.map(e=>e.name)],[`Schedules`,l.schedules.map(e=>e.name)]];return(0,P.jsxs)(`div`,{className:`application-designer`,children:[(0,P.jsxs)(`header`,{className:`designer-header`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`span`,{className:`eyebrow`,children:`Application fabric`}),(0,P.jsx)(`h1`,{children:l.app}),(0,P.jsx)(`p`,{children:`One model for state, intelligence, automation, security, and placement.`})]}),(0,P.jsxs)(`div`,{className:`designer-actions`,children:[(0,P.jsx)(`input`,{ref:ne,hidden:!0,type:`file`,accept:`.flow,text/plain`,onChange:e=>void pe(e.target.files?.[0])}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>ne.current?.click(),children:`Import`}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:fe,children:`Export`}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:k,children:`Version`}),(0,P.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>void ue(),children:`Apply locally`}),(0,P.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>te(e=>!e),children:`Publish to cloud`})]})]}),ae.some(e=>e.safety===`destructive`)&&(0,P.jsxs)(`label`,{className:`local-destructive`,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:w,onChange:e=>T(e.target.checked)}),(0,P.jsxs)(`span`,{children:[`Approve destructive local changes: `,ae.filter(e=>e.safety===`destructive`).map(e=>e.target).join(`, `)]})]}),ee&&(0,P.jsxs)(`form`,{className:`cloud-publisher`,onSubmit:e=>{e.preventDefault(),de()},children:[(0,P.jsxs)(`div`,{className:`cloud-publisher-heading`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`span`,{className:`eyebrow`,children:`Cloud release`}),(0,P.jsx)(`h2`,{children:`Publish this application model`}),(0,P.jsx)(`p`,{children:`FeltDB compares the cloud version, plans the migration, and publishes atomically.`})]}),(0,P.jsx)(`button`,{type:`button`,"aria-label":`Close cloud publisher`,onClick:()=>te(!1),children:`×`})]}),(0,P.jsxs)(`div`,{className:`cloud-fields`,children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`FeltDB Cloud URL`}),(0,P.jsx)(`input`,{type:`url`,placeholder:`https://your-instance.feltdb.cloud`,value:E.url,onChange:e=>D({...E,url:e.target.value,error:void 0,destructive:void 0,allowDestructive:!1})})]}),(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Namespace`}),(0,P.jsx)(`input`,{value:E.namespace,onChange:e=>D({...E,namespace:e.target.value,error:void 0,destructive:void 0,allowDestructive:!1})})]}),(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`API key`}),(0,P.jsx)(`input`,{type:`password`,autoComplete:`off`,placeholder:`Stored for this browser session only`,value:E.token,onChange:e=>D({...E,token:e.target.value,error:void 0})})]})]}),(E.destructive?.length||ae.some(e=>e.safety===`destructive`))&&(0,P.jsxs)(`label`,{className:`cloud-destructive`,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:E.allowDestructive,onChange:e=>D({...E,allowDestructive:e.target.checked})}),(0,P.jsxs)(`span`,{children:[`I reviewed and approve destructive model changes`,E.destructive?.length?`: ${E.destructive.join(`, `)}`:`.`]})]}),E.error&&(0,P.jsx)(`div`,{className:`cloud-error`,role:`alert`,children:E.error}),(0,P.jsxs)(`div`,{className:`cloud-actions`,children:[(0,P.jsx)(`button`,{type:`button`,className:`btn btn-ghost`,onClick:()=>te(!1),children:`Cancel`}),(0,P.jsx)(`button`,{className:`btn btn-primary`,disabled:E.publishing,type:`submit`,children:E.publishing?`Publishing…`:`Review and publish`})]})]}),(0,P.jsxs)(`div`,{className:`designer-status ${d.some(e=>e.severity===`error`)?`error`:``}`,children:[(0,P.jsx)(`span`,{children:h}),(0,P.jsxs)(`span`,{children:[l.collections.length,` collections · `,l.workflows.length,` workflows · `,p.length?`v${p.length}`:`draft`]})]}),(0,P.jsxs)(`div`,{className:`designer-grid`,children:[(0,P.jsxs)(`aside`,{className:`model-tree`,children:[(0,P.jsxs)(`div`,{className:`panel-title`,children:[(0,P.jsx)(`span`,{children:`Application`}),(0,P.jsx)(`button`,{"aria-label":`Add collection`,onClick:()=>C({name:``}),children:`+`})]}),S&&(0,P.jsxs)(`form`,{className:`collection-editor`,onSubmit:e=>{e.preventDefault(),se()},onKeyDown:e=>{e.key===`Escape`&&C(null)},children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`New collection`}),(0,P.jsx)(`input`,{autoFocus:!0,placeholder:`e.g. Customer`,value:S.name,onChange:e=>C({name:e.target.value})})]}),S.error&&(0,P.jsx)(`div`,{className:`field-error`,role:`alert`,children:S.error}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`button`,{type:`button`,onClick:()=>C(null),children:`Cancel`}),(0,P.jsx)(`button`,{className:`collection-save`,type:`submit`,children:`Add`})]})]}),me.map(([e,t])=>(0,P.jsxs)(`section`,{children:[(0,P.jsx)(`h3`,{children:e}),t.length?t.map(e=>(0,P.jsx)(`div`,{className:`tree-item`,children:e},e)):(0,P.jsx)(`div`,{className:`tree-empty`,children:`None`})]},e))]}),(0,P.jsxs)(`section`,{className:`model-canvas`,children:[(0,P.jsxs)(`div`,{className:`panel-title`,children:[(0,P.jsx)(`span`,{children:`Application graph`}),(0,P.jsx)(`span`,{className:`graph-legend`,children:`intent → fabric`})]}),(0,P.jsxs)(`div`,{className:`graph-board`,children:[l.collections.map(e=>(0,P.jsxs)(`article`,{className:`model-node`,children:[(0,P.jsx)(`div`,{className:`node-kind`,children:`collection`}),(0,P.jsx)(`h3`,{children:e.name}),e.fields.map(e=>(0,P.jsxs)(`div`,{className:`node-field`,children:[(0,P.jsx)(`span`,{children:e.name}),(0,P.jsxs)(`code`,{children:[e.type,e.optional?`?`:``]})]},e.name)),b?.collection===e.name?(0,P.jsxs)(`form`,{className:`field-editor`,onSubmit:e=>{e.preventDefault(),le()},onKeyDown:e=>{e.key===`Escape`&&x(null)},children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Field name`}),(0,P.jsx)(`input`,{autoFocus:!0,value:b.name,placeholder:`e.g. publishedAt`,onChange:e=>x({...b,name:e.target.value,error:void 0})})]}),(0,P.jsxs)(`div`,{className:`field-editor-row`,children:[(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Type`}),(0,P.jsxs)(`select`,{value:b.type,onChange:e=>x({...b,type:e.target.value,error:void 0}),children:[(0,P.jsx)(`option`,{value:`text`,children:`Text`}),(0,P.jsx)(`option`,{value:`integer`,children:`Integer`}),(0,P.jsx)(`option`,{value:`number`,children:`Number`}),(0,P.jsx)(`option`,{value:`decimal`,children:`Decimal`}),(0,P.jsx)(`option`,{value:`money`,children:`Money`}),(0,P.jsx)(`option`,{value:`bigint`,children:`Big integer`}),(0,P.jsx)(`option`,{value:`boolean`,children:`Boolean`}),(0,P.jsx)(`option`,{value:`datetime`,children:`Date & time`}),(0,P.jsx)(`option`,{value:`date`,children:`Date`}),(0,P.jsx)(`option`,{value:`time`,children:`Time`}),(0,P.jsx)(`option`,{value:`uuid`,children:`UUID`}),(0,P.jsx)(`option`,{value:`email`,children:`Email`}),(0,P.jsx)(`option`,{value:`url`,children:`URL`}),(0,P.jsx)(`option`,{value:`phone`,children:`Phone`}),(0,P.jsx)(`option`,{value:`json`,children:`JSON`}),(0,P.jsx)(`option`,{value:`object`,children:`Object`}),(0,P.jsx)(`option`,{value:`binary`,children:`Binary`}),(0,P.jsx)(`option`,{value:`file`,children:`File`}),(0,P.jsx)(`option`,{value:`geo`,children:`Geo point`}),(0,P.jsx)(`option`,{value:`enum`,children:`Enum`}),(0,P.jsx)(`option`,{value:`array`,children:`Array`}),(0,P.jsx)(`option`,{value:`map`,children:`Typed map`}),(0,P.jsx)(`option`,{value:`vector`,children:`Vector`}),(0,P.jsx)(`option`,{value:`ref`,children:`Reference`})]})]}),b.type===`ref`&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Collection`}),(0,P.jsx)(`select`,{value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0}),children:l.collections.filter(t=>t.name!==e.name).map(e=>(0,P.jsx)(`option`,{value:e.name,children:e.name},e.name))})]}),b.type===`enum`&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Values`}),(0,P.jsx)(`input`,{placeholder:`draft,active,done`,value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0})})]}),(b.type===`array`||b.type===`map`)&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Item type`}),(0,P.jsx)(`input`,{placeholder:`text, uuid, ref Project…`,value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0})})]}),b.type===`vector`&&(0,P.jsxs)(`label`,{children:[(0,P.jsx)(`span`,{children:`Dimensions`}),(0,P.jsx)(`input`,{type:`number`,min:`1`,placeholder:`1536`,value:b.reference,onChange:e=>x({...b,reference:e.target.value,error:void 0})})]})]}),(0,P.jsxs)(`label`,{className:`field-optional`,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:b.optional,onChange:e=>x({...b,optional:e.target.checked})}),(0,P.jsx)(`span`,{children:`Optional field`})]}),b.error&&(0,P.jsx)(`div`,{className:`field-error`,role:`alert`,children:b.error}),(0,P.jsxs)(`div`,{className:`field-editor-actions`,children:[(0,P.jsx)(`button`,{type:`button`,onClick:()=>x(null),children:`Cancel`}),(0,P.jsx)(`button`,{className:`field-save`,type:`submit`,children:`Add field`})]})]}):(0,P.jsx)(`button`,{className:`node-add`,onClick:()=>ce(e.name),children:`+ field`})]},e.name)),l.workflows.map(e=>(0,P.jsxs)(`article`,{className:`model-node workflow-node`,children:[(0,P.jsx)(`div`,{className:`node-kind`,children:`workflow`}),(0,P.jsx)(`h3`,{children:e.name}),e.steps.map(e=>(0,P.jsx)(`div`,{className:`node-step`,children:e.name},e.name))]},e.name)),l.agents.map(e=>(0,P.jsxs)(`article`,{className:`model-node agent-node`,children:[(0,P.jsx)(`div`,{className:`node-kind`,children:`agent`}),(0,P.jsx)(`h3`,{children:e.name}),e.statements.map(e=>(0,P.jsx)(`div`,{className:`node-step`,children:e},e))]},e.name))]}),(0,P.jsxs)(`div`,{className:`change-strip`,children:[(0,P.jsx)(`strong`,{children:`Model diff`}),(0,P.jsxs)(`span`,{className:`added`,children:[`+ `,ie.added.join(`, `)||`none`]}),(0,P.jsxs)(`span`,{className:`changed`,children:[`~ `,ie.changed.join(`, `)||`none`]}),(0,P.jsxs)(`span`,{className:`removed`,children:[`− `,ie.removed.join(`, `)||`none`]})]})]}),(0,P.jsxs)(`section`,{className:`dsl-panel`,children:[(0,P.jsxs)(`div`,{className:`panel-title`,children:[(0,P.jsx)(`span`,{children:`Flow DSL`}),(0,P.jsx)(`span`,{children:`feltdb.flow`})]}),(0,P.jsx)(`textarea`,{"aria-label":`Flow DSL`,spellCheck:!1,value:s,onChange:e=>O(e.target.value)}),d.length>0&&(0,P.jsx)(`div`,{className:`diagnostics`,children:d.map((e,t)=>(0,P.jsxs)(`div`,{className:e.severity,children:[e.severity,`: `,e.message]},t))})]})]})]})}var z={panel:`_panel_1cbba_1`,header:`_header_1cbba_8`,createButton:`_createButton_1cbba_23`,error:`_error_1cbba_38`,createForm:`_createForm_1cbba_47`,formGroup:`_formGroup_1cbba_55`,scopeList:`_scopeList_1cbba_76`,scopeCheckbox:`_scopeCheckbox_1cbba_82`,submitButton:`_submitButton_1cbba_94`,empty:`_empty_1cbba_109`,keysList:`_keysList_1cbba_117`,keyCard:`_keyCard_1cbba_123`,keyHeader:`_keyHeader_1cbba_135`,namespace:`_namespace_1cbba_150`,status:`_status_1cbba_156`,active:`_active_1cbba_163`,expired:`_expired_1cbba_168`,keyDetails:`_keyDetails_1cbba_173`,detail:`_detail_1cbba_179`,copyBtn:`_copyBtn_1cbba_203`,daysLeft:`_daysLeft_1cbba_217`,scopes:`_scopes_1cbba_223`,scopeTags:`_scopeTags_1cbba_227`,scopeTag:`_scopeTag_1cbba_227`,keyActions:`_keyActions_1cbba_243`,revokeBtn:`_revokeBtn_1cbba_250`,info:`_info_1cbba_265`},yi=({apiUrl:e,token:t,namespace:n=`app-store-sherpa`,onConfigure:r})=>{let[i,a]=(0,g.useState)([]),[o,s]=(0,g.useState)(!0),[c,l]=(0,g.useState)(null),[u,d]=(0,g.useState)(!1),[f,p]=(0,g.useState)(null),[m,h]=(0,g.useState)(``),[_,v]=(0,g.useState)([`state:read`,`state:write`,`events:read`]),y=[`state:read`,`state:write`,`events:read`,`backup:create`,`backup:restore`,`admin:logs`,`admin:restart`],b=[`state:read`,`state:write`,`events:read`,`backup:create`,`backup:restore`,`admin:logs`,`admin:restart`];(0,g.useEffect)(()=>{x()},[e,t]);let x=async()=>{try{if(s(!0),l(null),!e){l(`A server or managed API URL is not configured.`),s(!1);return}let n=await fetch(`${e}/api/keys`,{headers:t?{Authorization:`Bearer ${t}`}:{},signal:AbortSignal.timeout(1e4)});if(n.status===401)throw Error(`Unauthorized: Invalid or expired API token`);if(n.status===403)throw Error(`Forbidden: Your account does not have permission to manage API keys`);if(!n.ok)throw Error(`Failed to fetch keys: ${n.status} ${n.statusText}`);let r=await n.json();a(r.tokens||[])}catch(t){let n=t instanceof TypeError?`Connection error: Unable to reach ${e}. Is the server running?`:t instanceof Error?t.message:`Failed to fetch keys`;l(n),console.error(`Error fetching API keys:`,t)}finally{s(!1)}},S=async r=>{r.preventDefault();try{let r=await fetch(`${e}/api/keys`,{method:`POST`,headers:{...t?{Authorization:`Bearer ${t}`}:{},"Content-Type":`application/json`},body:JSON.stringify({id:m||`key-${Date.now()}`,namespace:n,scopes:_.length>0?_:b}),signal:AbortSignal.timeout(1e4)});if(r.status===401)throw Error(`Unauthorized: Invalid or expired API token`);if(r.status===409)throw Error(`A key with this name already exists`);if(!r.ok)throw Error(`Failed to create key: ${r.status} ${r.statusText}`);let i=await r.json();ee(i.secret),h(``),v(b),d(!1),await x()}catch(e){let t=e instanceof TypeError?`Connection error: Unable to reach the API server`:e instanceof Error?e.message:`Failed to create key`;l(t),console.error(`Error creating API key:`,e)}},C=async n=>{if(confirm(`Revoke key "${n}"? This cannot be undone.`))try{let r=await fetch(`${e}/api/keys/${n}`,{method:`DELETE`,headers:t?{Authorization:`Bearer ${t}`}:{},signal:AbortSignal.timeout(1e4)});if(r.status===404)throw Error(`Key not found`);if(r.status===401)throw Error(`Unauthorized: Invalid or expired API token`);if(!r.ok)throw Error(`Failed to revoke key: ${r.status} ${r.statusText}`);await x()}catch(e){let t=e instanceof TypeError?`Connection error: Unable to reach the API server`:e instanceof Error?e.message:`Failed to revoke key`;l(t),console.error(`Error revoking API key:`,e)}},w=(e,t)=>{navigator.clipboard.writeText(e),p(t),setTimeout(()=>p(null),2e3)},[T,ee]=(0,g.useState)(null);return o?(0,P.jsx)(`div`,{className:z.panel,children:`Loading keys...`}):(0,P.jsxs)(`div`,{className:z.panel,children:[(0,P.jsxs)(`div`,{className:z.header,children:[(0,P.jsx)(`h2`,{children:`API Key Management`}),(0,P.jsx)(`button`,{className:z.createButton,onClick:()=>d(!u),disabled:!e,children:u?`✕ Cancel`:`+ New Key`})]}),c&&(0,P.jsxs)(`div`,{className:z.error,children:[(0,P.jsxs)(`strong`,{children:[`⚠ `,c]}),(0,P.jsx)(`div`,{style:{fontSize:`12px`,marginTop:`8px`,lineHeight:`1.5`},children:c.includes(`Connection error`)&&(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(`p`,{children:`To use API key management, ensure:`}),(0,P.jsxs)(`ul`,{style:{margin:`4px 0`,paddingLeft:`20px`},children:[(0,P.jsxs)(`li`,{children:[`FeltDB server is running on `,(0,P.jsx)(`code`,{children:e})]}),(0,P.jsx)(`li`,{children:`VITE_FELTDB_URL environment variable is set correctly`}),(0,P.jsx)(`li`,{children:`Your API token has proper scopes`})]}),(0,P.jsx)(`button`,{onClick:()=>x(),style:{marginTop:`8px`,padding:`4px 12px`,fontSize:`12px`,background:`#667eea`,color:`white`,border:`none`,borderRadius:`4px`,cursor:`pointer`},children:`Retry`})]})})]}),!e&&(0,P.jsxs)(`div`,{className:z.error,children:[(0,P.jsx)(`strong`,{children:`Connect Studio to a server or managed runtime before managing keys.`}),r&&(0,P.jsx)(`button`,{onClick:r,children:`Open connection settings`})]}),T&&(0,P.jsxs)(`div`,{className:z.info,children:[(0,P.jsx)(`strong`,{children:`New secret — copy it now; it will not be shown again.`}),(0,P.jsx)(`code`,{children:T}),(0,P.jsx)(`button`,{onClick:()=>w(T,`created`),children:f===`created`?`✓ Copied`:`Copy secret`})]}),u&&(0,P.jsxs)(`form`,{onSubmit:S,className:z.createForm,children:[(0,P.jsxs)(`div`,{className:z.formGroup,children:[(0,P.jsx)(`label`,{children:`Key Name (optional)`}),(0,P.jsx)(`input`,{type:`text`,value:m,onChange:e=>h(e.target.value),placeholder:`e.g., staging-key-001`})]}),(0,P.jsxs)(`div`,{className:z.formGroup,children:[(0,P.jsx)(`label`,{children:`Scopes`}),(0,P.jsx)(`div`,{className:z.scopeList,children:y.map(e=>(0,P.jsxs)(`label`,{className:z.scopeCheckbox,children:[(0,P.jsx)(`input`,{type:`checkbox`,checked:_.includes(e),onChange:t=>{t.target.checked?v([..._,e]):v(_.filter(t=>t!==e))}}),e]},e))})]}),(0,P.jsx)(`button`,{type:`submit`,className:z.submitButton,children:`Create Key`})]}),i.length===0?(0,P.jsx)(`div`,{className:z.empty,children:`No API keys configured. Create one to get started.`}):(0,P.jsx)(`div`,{className:z.keysList,children:i.map(e=>(0,P.jsxs)(`div`,{className:z.keyCard,children:[(0,P.jsxs)(`div`,{className:z.keyHeader,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`h3`,{children:e.name||e.id}),(0,P.jsxs)(`p`,{className:z.namespace,children:[`Namespaces: `,e.namespaces.join(`, `)]})]}),(0,P.jsx)(`span`,{className:`${z.status} ${e.revoked?z.expired:z.active}`,children:e.revoked?`Revoked`:`Active`})]}),(0,P.jsx)(`div`,{className:z.keyDetails,children:(0,P.jsxs)(`div`,{className:z.scopes,children:[(0,P.jsx)(`strong`,{children:`Scopes:`}),(0,P.jsx)(`div`,{className:z.scopeTags,children:e.scopes.map(e=>(0,P.jsx)(`span`,{className:z.scopeTag,children:e},e))})]})}),(0,P.jsx)(`div`,{className:z.keyActions,children:(0,P.jsx)(`button`,{className:z.revokeBtn,onClick:()=>C(e.id),disabled:e.revoked,children:`Revoke`})})]},e.id))}),(0,P.jsx)(`div`,{className:z.info,children:(0,P.jsxs)(`p`,{children:[(0,P.jsx)(`strong`,{children:`Security:`}),` Store tokens securely. Never commit to version control. Secrets are shown once. Revoke and replace a key if its secret is lost.`]})})]})};function bi({db:e,remoteUrl:t=``,token:n=``,namespace:r=`default`,deploymentRuntime:i=`browser`,applicationUrl:a=``,onConnect:o}){let[s,c]=(0,g.useState)(null),l=In(e||null,r),u=Ln(e||null,s,r),{diagnostics:d}=Rn(e||null),f=Bn(e||null),[p,m]=(0,g.useState)(),h=i!==`browser`||!!t,_=e=>({pathname:e,search:window.location.search});return(0,g.useEffect)(()=>{let t=!0;return fetch(`/_feltdb/project`,{cache:`no-store`}).then(async e=>{if(!e.ok)throw Error(`No project model endpoint`);let n=await e.json();t&&c(Br(n.source))}).catch(async()=>{let n=e?await e.collection(`_flow_apps`).all():[];t&&n[0]?.spec&&c(n[0].spec)}),()=>{t=!1}},[e]),(0,P.jsx)(Cn,{children:(0,P.jsxs)(`div`,{className:`studio-app`,children:[(0,P.jsxs)(`nav`,{className:`studio-nav`,children:[(0,P.jsxs)(`div`,{className:`nav-header`,children:[(0,P.jsx)(`h1`,{children:`FeltDB Studio`}),l&&(0,P.jsx)(`div`,{className:`instance-info`,children:l.namespace})]}),(0,P.jsx)(`div`,{className:`nav-search`,children:(0,P.jsx)(nr,{db:e,model:s})}),(0,P.jsxs)(`ul`,{className:`nav-menu`,children:[(0,P.jsx)(`li`,{className:`nav-section`,children:`Design`}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/`),children:`Application`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/capabilities`),children:`Capabilities`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/workflows`),children:`Workflows`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/agents`),children:`Agents`})}),(0,P.jsx)(`li`,{className:`nav-section`,children:`Observe`}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/overview`),children:`Overview`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/data`),children:`Data`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/references`),children:`References`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/operations`),children:`Operations`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/executions`),children:`Executions`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/peers`),children:`Peers`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/provenance`),children:`Provenance`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/conflicts`),children:`Conflicts`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/health`),children:`Health`})}),(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/settings`),children:`Settings`})}),h&&(0,P.jsx)(`li`,{children:(0,P.jsx)(N,{to:_(`/api-keys`),children:`API Keys`})})]})]}),(0,P.jsxs)(`main`,{className:`studio-content`,children:[!h&&(0,P.jsx)(`div`,{className:`runtime-notice`,children:`Browser data is read live from the generated application origin through the local Studio bridge.`}),(0,P.jsxs)(zt,{children:[(0,P.jsx)(j,{path:`/`,element:(0,P.jsx)(vi,{db:e,namespace:r,projectSpec:s,onSpecChange:c})}),(0,P.jsx)(j,{path:`/overview`,element:(0,P.jsx)(Fn,{stats:u})}),(0,P.jsx)(j,{path:`/data`,element:(0,P.jsx)(Hn,{db:e,model:s,namespace:r,applicationUrl:i===`browser`?a:``})}),(0,P.jsx)(j,{path:`/state`,element:(0,P.jsx)(Hn,{db:e,model:s,namespace:r,applicationUrl:i===`browser`?a:``})}),(0,P.jsx)(j,{path:`/references`,element:(0,P.jsx)(Wn,{db:e,model:s,namespace:r})}),(0,P.jsx)(j,{path:`/operations`,element:(0,P.jsx)(Gn,{db:e,model:s,namespace:r})}),(0,P.jsx)(j,{path:`/peers`,element:(0,P.jsx)(Kn,{peers:f,localInstance:l?.instanceId})}),(0,P.jsx)(j,{path:`/capabilities`,element:(0,P.jsx)(qn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/executions`,element:(0,P.jsx)(Yn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/workflows`,element:(0,P.jsx)(Zn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/agents`,element:(0,P.jsx)(Qn,{db:e,model:s})}),(0,P.jsx)(j,{path:`/provenance`,element:(0,P.jsx)($n,{db:e,model:s,namespace:r,reference:p})}),(0,P.jsx)(j,{path:`/conflicts`,element:(0,P.jsx)(Xn,{db:e,diagnostics:d})}),(0,P.jsx)(j,{path:`/health`,element:(0,P.jsx)(er,{diagnostics:d,model:s})}),(0,P.jsx)(j,{path:`/settings`,element:(0,P.jsx)(tr,{db:e,remoteUrl:t,token:n,onConnect:o})}),(0,P.jsx)(j,{path:`/api-keys`,element:(0,P.jsxs)(`div`,{style:{padding:`2rem`},children:[(0,P.jsx)(`h1`,{children:`API Key Management`}),(0,P.jsx)(yi,{apiUrl:t,token:n,namespace:r,onConfigure:()=>window.location.assign(`/settings`)})]})})]})]})]})})}var xi=new URLSearchParams(window.location.search),Si=xi.get(`connect`)||``,Ci=xi.get(`namespace`)||`default`,wi=xi.get(`runtime`)||(Si?`remote`:`browser`),Ti=xi.get(`app`)||``;function Ei(){let[e,t]=(0,g.useState)(Si),[n,r]=(0,g.useState)(()=>Si?window.sessionStorage.getItem(`feltdb-token:${Si}`):``);g.useEffect(()=>{if(!Si||n!==null)return;let e=!0;return fetch(`/_feltdb/config`,{cache:`no-store`}).then(async e=>e.ok?e.json():{}).then(t=>{if(!e)return;let n=t.token||``;n&&window.sessionStorage.setItem(`feltdb-token:${Si}`,n),r(n)}).catch(()=>{e&&r(``)}),()=>{e=!1}},[n]);let i=(0,g.useMemo)(()=>n===null?null:window.feltdb||fi(e?{namespace:Ci,server:{url:e,token:n}}:{namespace:Ci,browser:!0}),[e,n]);return n===null?(0,P.jsx)(`div`,{style:{padding:`2rem`},children:`Connecting Studio…`}):(0,P.jsx)(bi,{db:i||void 0,remoteUrl:e,token:n,namespace:Ci,deploymentRuntime:wi,applicationUrl:Ti,onConnect:(e,n)=>{let i=e.trim().replace(/\/$/,``);i&&n&&window.sessionStorage.setItem(`feltdb-token:${i}`,n),t(i),r(n)}})}_.createRoot(document.getElementById(`root`)).render((0,P.jsx)(g.StrictMode,{children:(0,P.jsx)(Ei,{})}));
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#17211b"/><title>FeltDB Studio</title> <script type="module" crossorigin src="/assets/index-
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#17211b"/><title>FeltDB Studio</title> <script type="module" crossorigin src="/assets/index-BF45M757.js"></script>
|
|
2
2
|
<link rel="stylesheet" crossorigin href="/assets/index-C1GWyazR.css">
|
|
3
3
|
</head><body><div id="root"></div></body></html>
|
package/dist/telemetry.js
CHANGED
|
@@ -158,7 +158,7 @@ export class TelemetryClient {
|
|
|
158
158
|
*/
|
|
159
159
|
async sendEvents(events) {
|
|
160
160
|
const endpoint = environmentValue('FELTDB_TELEMETRY_ENDPOINT') ||
|
|
161
|
-
'https://
|
|
161
|
+
'https://feltdb.com/api/v1/telemetry/events';
|
|
162
162
|
// Timeout after 3 seconds - don't block application
|
|
163
163
|
const controller = new AbortController();
|
|
164
164
|
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* to a FeltDB Development Workspace.
|
|
6
6
|
*/
|
|
7
7
|
import type { ClientType } from './workspace-types.js';
|
|
8
|
+
import type { WorkspaceEventPayload } from './workspace-types.js';
|
|
8
9
|
export interface WorkspaceConnectionOptions {
|
|
9
10
|
pairingCode?: string;
|
|
10
11
|
workspaceId?: string;
|
|
@@ -26,6 +27,7 @@ export interface PairingTokenData {
|
|
|
26
27
|
token: string;
|
|
27
28
|
workspaceId: string;
|
|
28
29
|
expiresAt: number;
|
|
30
|
+
endpoint?: string;
|
|
29
31
|
}
|
|
30
32
|
export interface ClientInfo {
|
|
31
33
|
clientId: string;
|
|
@@ -101,8 +103,9 @@ export declare class DevelopmentWorkspaceConnection {
|
|
|
101
103
|
clientType: ClientType;
|
|
102
104
|
private options;
|
|
103
105
|
private subscriptions;
|
|
104
|
-
|
|
105
|
-
private
|
|
106
|
+
connectedAt: number;
|
|
107
|
+
private transport;
|
|
108
|
+
private unsubscribeEvents;
|
|
106
109
|
constructor(workspaceId: string, clientId: string, clientType: ClientType, options: WorkspaceConnectionOptions);
|
|
107
110
|
/**
|
|
108
111
|
* Establish connection to workspace
|
|
@@ -112,10 +115,6 @@ export declare class DevelopmentWorkspaceConnection {
|
|
|
112
115
|
* Close connection to workspace
|
|
113
116
|
*/
|
|
114
117
|
disconnect(): Promise<void>;
|
|
115
|
-
/**
|
|
116
|
-
* Register this client as connected
|
|
117
|
-
*/
|
|
118
|
-
private registerClient;
|
|
119
118
|
/**
|
|
120
119
|
* Get capabilities for this client type
|
|
121
120
|
*/
|
|
@@ -123,7 +122,7 @@ export declare class DevelopmentWorkspaceConnection {
|
|
|
123
122
|
/**
|
|
124
123
|
* List connected clients in workspace
|
|
125
124
|
*/
|
|
126
|
-
clients(): ClientInfo[]
|
|
125
|
+
clients(): Promise<ClientInfo[]>;
|
|
127
126
|
/**
|
|
128
127
|
* Subscribe to workspace entity changes
|
|
129
128
|
*
|
|
@@ -157,18 +156,7 @@ export declare class DevelopmentWorkspaceConnection {
|
|
|
157
156
|
* Notify subscribers of entity changes
|
|
158
157
|
*/
|
|
159
158
|
private notifySubscribers;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
* Event payload for workspace changes
|
|
163
|
-
*/
|
|
164
|
-
export interface WorkspaceEventPayload<T = unknown> {
|
|
165
|
-
id: string;
|
|
166
|
-
workspaceId: string;
|
|
167
|
-
collection: string;
|
|
168
|
-
entityId: string;
|
|
169
|
-
type: 'created' | 'updated' | 'deleted';
|
|
170
|
-
value?: T;
|
|
171
|
-
timestamp: number;
|
|
172
|
-
originClientId: string;
|
|
159
|
+
private requireTransport;
|
|
160
|
+
private resolveEndpoint;
|
|
173
161
|
}
|
|
174
162
|
//# sourceMappingURL=workspace-connection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-connection.d.ts","sourceRoot":"","sources":["../../src/workspace/workspace-connection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-connection.d.ts","sourceRoot":"","sources":["../../src/workspace/workspace-connection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAgB5B;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,8BAA8B,CAAC,CA+BzC;AAYD;;;;;GAKG;AACH,qBAAa,8BAA8B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,aAAa,CAA4E;IACjG,WAAW,EAAE,MAAM,CAAK;IACxB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,iBAAiB,CAA6B;gBAGpD,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,0BAA0B;IAQrC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAevB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAItC;;;;;;;;;OASG;IACH,SAAS,CAAC,CAAC,GAAG,OAAO,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,GACjD,MAAM,IAAI;IAgBb;;;;OAIG;IACG,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAY/E;;OAEG;IACG,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAIrE;;OAEG;IACG,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAIhD;;OAEG;IACG,MAAM,CAAC,CAAC,SAAS,MAAM,EAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAClB,OAAO,CAAC,IAAI,CAAC;IAUhB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,gBAAgB;YAKV,eAAe;CAa9B"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import fs from 'fs';
|
|
8
8
|
import path from 'path';
|
|
9
|
+
import { HttpJsDb } from '../http-db.js';
|
|
9
10
|
/**
|
|
10
11
|
* Discover workspace from .feltdb/workspace.json
|
|
11
12
|
*
|
|
@@ -109,7 +110,9 @@ export async function connectDevelopmentWorkspace(options) {
|
|
|
109
110
|
}
|
|
110
111
|
const clientId = options.clientId || generateClientId(options.clientType);
|
|
111
112
|
const clientType = options.clientType || 'other';
|
|
112
|
-
|
|
113
|
+
const connection = new DevelopmentWorkspaceConnection(workspaceId, clientId, clientType, options);
|
|
114
|
+
await connection.connect();
|
|
115
|
+
return connection;
|
|
113
116
|
}
|
|
114
117
|
/**
|
|
115
118
|
* Generate a unique client ID based on type
|
|
@@ -130,7 +133,8 @@ export class DevelopmentWorkspaceConnection {
|
|
|
130
133
|
constructor(workspaceId, clientId, clientType, options) {
|
|
131
134
|
this.subscriptions = new Map();
|
|
132
135
|
this.connectedAt = 0;
|
|
133
|
-
this.
|
|
136
|
+
this.transport = null;
|
|
137
|
+
this.unsubscribeEvents = null;
|
|
134
138
|
this.workspaceId = workspaceId;
|
|
135
139
|
this.clientId = clientId;
|
|
136
140
|
this.clientType = clientType;
|
|
@@ -140,26 +144,34 @@ export class DevelopmentWorkspaceConnection {
|
|
|
140
144
|
* Establish connection to workspace
|
|
141
145
|
*/
|
|
142
146
|
async connect() {
|
|
143
|
-
this.
|
|
144
|
-
|
|
147
|
+
if (this.transport)
|
|
148
|
+
return;
|
|
149
|
+
const endpoint = await this.resolveEndpoint();
|
|
150
|
+
const transport = new HttpWorkspaceTransport(endpoint, this.options.auth?.token ?? '');
|
|
151
|
+
await transport.assertReachable();
|
|
152
|
+
const connectedAt = Date.now();
|
|
153
|
+
await transport.registerClient(this.workspaceId, {
|
|
154
|
+
clientId: this.clientId,
|
|
155
|
+
clientType: this.clientType,
|
|
156
|
+
connectedAt,
|
|
157
|
+
capabilities: this.getCapabilities(),
|
|
158
|
+
});
|
|
159
|
+
this.transport = transport;
|
|
160
|
+
this.unsubscribeEvents = transport.subscribe(this.workspaceId, event => this.notifySubscribers(event));
|
|
161
|
+
this.connectedAt = connectedAt;
|
|
145
162
|
}
|
|
146
163
|
/**
|
|
147
164
|
* Close connection to workspace
|
|
148
165
|
*/
|
|
149
166
|
async disconnect() {
|
|
167
|
+
this.unsubscribeEvents?.();
|
|
168
|
+
this.unsubscribeEvents = null;
|
|
169
|
+
if (this.transport) {
|
|
170
|
+
await this.transport.unregisterClient(this.workspaceId, this.clientId);
|
|
171
|
+
}
|
|
150
172
|
this.subscriptions.clear();
|
|
151
|
-
this.
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Register this client as connected
|
|
155
|
-
*/
|
|
156
|
-
registerClient() {
|
|
157
|
-
this.connectedClients.set(this.clientId, {
|
|
158
|
-
clientId: this.clientId,
|
|
159
|
-
clientType: this.clientType,
|
|
160
|
-
connectedAt: this.connectedAt,
|
|
161
|
-
capabilities: this.getCapabilities(),
|
|
162
|
-
});
|
|
173
|
+
this.transport = null;
|
|
174
|
+
this.connectedAt = 0;
|
|
163
175
|
}
|
|
164
176
|
/**
|
|
165
177
|
* Get capabilities for this client type
|
|
@@ -181,8 +193,8 @@ export class DevelopmentWorkspaceConnection {
|
|
|
181
193
|
/**
|
|
182
194
|
* List connected clients in workspace
|
|
183
195
|
*/
|
|
184
|
-
clients() {
|
|
185
|
-
return
|
|
196
|
+
async clients() {
|
|
197
|
+
return this.requireTransport().clients(this.workspaceId);
|
|
186
198
|
}
|
|
187
199
|
/**
|
|
188
200
|
* Subscribe to workspace entity changes
|
|
@@ -214,56 +226,44 @@ export class DevelopmentWorkspaceConnection {
|
|
|
214
226
|
*/
|
|
215
227
|
async publish(collection, entity) {
|
|
216
228
|
const id = generateEntityId();
|
|
217
|
-
|
|
218
|
-
id: generateEventId(),
|
|
229
|
+
await this.requireTransport().publish({
|
|
219
230
|
workspaceId: this.workspaceId,
|
|
220
231
|
collection,
|
|
221
232
|
entityId: id,
|
|
222
|
-
type: 'created',
|
|
223
233
|
value: entity,
|
|
224
|
-
timestamp: Date.now(),
|
|
225
234
|
originClientId: this.clientId,
|
|
226
|
-
};
|
|
227
|
-
this.notifySubscribers(collection, event);
|
|
235
|
+
});
|
|
228
236
|
return id;
|
|
229
237
|
}
|
|
230
238
|
/**
|
|
231
239
|
* Get entity from workspace
|
|
232
240
|
*/
|
|
233
241
|
async get(collection, entityId) {
|
|
234
|
-
|
|
235
|
-
// For now, returns null (placeholder)
|
|
236
|
-
return null;
|
|
242
|
+
return this.requireTransport().get({ workspaceId: this.workspaceId, collection, entityId });
|
|
237
243
|
}
|
|
238
244
|
/**
|
|
239
245
|
* Query entities in workspace collection
|
|
240
246
|
*/
|
|
241
247
|
async query(collection) {
|
|
242
|
-
|
|
243
|
-
// For now, returns empty array (placeholder)
|
|
244
|
-
return [];
|
|
248
|
+
return this.requireTransport().query({ workspaceId: this.workspaceId, collection });
|
|
245
249
|
}
|
|
246
250
|
/**
|
|
247
251
|
* Update entity in workspace
|
|
248
252
|
*/
|
|
249
253
|
async update(collection, entityId, updates) {
|
|
250
|
-
|
|
251
|
-
id: generateEventId(),
|
|
254
|
+
await this.requireTransport().update({
|
|
252
255
|
workspaceId: this.workspaceId,
|
|
253
256
|
collection,
|
|
254
257
|
entityId,
|
|
255
|
-
|
|
256
|
-
value: updates,
|
|
257
|
-
timestamp: Date.now(),
|
|
258
|
+
updates,
|
|
258
259
|
originClientId: this.clientId,
|
|
259
|
-
};
|
|
260
|
-
this.notifySubscribers(collection, event);
|
|
260
|
+
});
|
|
261
261
|
}
|
|
262
262
|
/**
|
|
263
263
|
* Notify subscribers of entity changes
|
|
264
264
|
*/
|
|
265
|
-
notifySubscribers(
|
|
266
|
-
const handlers = this.subscriptions.get(collection);
|
|
265
|
+
notifySubscribers(event) {
|
|
266
|
+
const handlers = this.subscriptions.get(event.collection);
|
|
267
267
|
if (handlers) {
|
|
268
268
|
for (const handler of handlers) {
|
|
269
269
|
try {
|
|
@@ -275,6 +275,27 @@ export class DevelopmentWorkspaceConnection {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
+
requireTransport() {
|
|
279
|
+
if (!this.transport)
|
|
280
|
+
throw new Error('Development Workspace is not connected');
|
|
281
|
+
return this.transport;
|
|
282
|
+
}
|
|
283
|
+
async resolveEndpoint() {
|
|
284
|
+
if (this.options.endpoint)
|
|
285
|
+
return this.options.endpoint;
|
|
286
|
+
const environmentEndpoint = typeof process !== 'undefined'
|
|
287
|
+
? process.env.FELTDB_WORKSPACE_ENDPOINT || process.env.VITE_FELTDB_URL
|
|
288
|
+
: undefined;
|
|
289
|
+
if (environmentEndpoint)
|
|
290
|
+
return environmentEndpoint;
|
|
291
|
+
if (this.options.pairingCode && this.options.projectDir) {
|
|
292
|
+
const pairingPath = path.join(this.options.projectDir, '.feltdb', 'pairing.json');
|
|
293
|
+
const pairing = JSON.parse(fs.readFileSync(pairingPath, 'utf8'));
|
|
294
|
+
if (pairing.endpoint)
|
|
295
|
+
return pairing.endpoint;
|
|
296
|
+
}
|
|
297
|
+
throw new Error('Cannot connect: workspace authority endpoint is required');
|
|
298
|
+
}
|
|
278
299
|
}
|
|
279
300
|
/**
|
|
280
301
|
* Generate unique entity ID
|
|
@@ -288,3 +309,108 @@ function generateEntityId() {
|
|
|
288
309
|
function generateEventId() {
|
|
289
310
|
return `event_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
290
311
|
}
|
|
312
|
+
const ENTITY_COLLECTION = '_development_workspace_entities';
|
|
313
|
+
const EVENT_COLLECTION = '_development_workspace_events';
|
|
314
|
+
const CLIENT_COLLECTION = '_development_workspace_clients';
|
|
315
|
+
class HttpWorkspaceTransport {
|
|
316
|
+
constructor(endpoint, token) {
|
|
317
|
+
this.seenEvents = new Set();
|
|
318
|
+
this.db = new HttpJsDb({ url: endpoint, token });
|
|
319
|
+
}
|
|
320
|
+
async assertReachable() {
|
|
321
|
+
const result = await this.db.query(ENTITY_COLLECTION);
|
|
322
|
+
if (!result.success)
|
|
323
|
+
throw new Error(`Workspace authority unavailable: ${result.error}`);
|
|
324
|
+
}
|
|
325
|
+
async registerClient(workspaceId, client) {
|
|
326
|
+
const result = await this.db.insert(`${CLIENT_COLLECTION}:${recordId(workspaceId, client.clientId)}`, JSON.stringify({ workspaceId, ...client }));
|
|
327
|
+
if (!result.success) {
|
|
328
|
+
const update = await this.db.update(`${CLIENT_COLLECTION}:${recordId(workspaceId, client.clientId)}`, JSON.stringify({ workspaceId, ...client }));
|
|
329
|
+
if (!update.success)
|
|
330
|
+
throw new Error(`Client registration failed: ${update.error}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async unregisterClient(workspaceId, clientId) {
|
|
334
|
+
const result = await this.db.delete(`${CLIENT_COLLECTION}:${recordId(workspaceId, clientId)}`);
|
|
335
|
+
if (!result.success && !String(result.error).includes('404'))
|
|
336
|
+
throw new Error(`Client cleanup failed: ${result.error}`);
|
|
337
|
+
}
|
|
338
|
+
async clients(workspaceId) {
|
|
339
|
+
return (await this.readCollection(CLIENT_COLLECTION))
|
|
340
|
+
.filter(client => client.workspaceId === workspaceId);
|
|
341
|
+
}
|
|
342
|
+
async publish(input) {
|
|
343
|
+
const envelope = { ...input, updatedAt: Date.now() };
|
|
344
|
+
const stored = await this.db.insert(`${ENTITY_COLLECTION}:${recordId(input.workspaceId, input.collection, input.entityId)}`, JSON.stringify(envelope));
|
|
345
|
+
if (!stored.success)
|
|
346
|
+
throw new Error(`Workspace publish failed: ${stored.error}`);
|
|
347
|
+
await this.appendEvent(input, 'created', input.value);
|
|
348
|
+
}
|
|
349
|
+
async get(input) {
|
|
350
|
+
const result = await this.db.get(`${ENTITY_COLLECTION}:${recordId(input.workspaceId, input.collection, input.entityId)}`);
|
|
351
|
+
if (!result.success)
|
|
352
|
+
throw new Error(`Workspace get failed: ${result.error}`);
|
|
353
|
+
if (!result.data)
|
|
354
|
+
return null;
|
|
355
|
+
const envelope = JSON.parse(result.data);
|
|
356
|
+
return envelope.workspaceId === input.workspaceId && envelope.collection === input.collection ? envelope.value : null;
|
|
357
|
+
}
|
|
358
|
+
async query(input) {
|
|
359
|
+
return (await this.readCollection(ENTITY_COLLECTION))
|
|
360
|
+
.filter(entity => entity.workspaceId === input.workspaceId && entity.collection === input.collection)
|
|
361
|
+
.map(entity => entity.value);
|
|
362
|
+
}
|
|
363
|
+
async update(input) {
|
|
364
|
+
const current = await this.get(input);
|
|
365
|
+
if (current === null)
|
|
366
|
+
throw new Error(`Workspace entity not found: ${input.entityId}`);
|
|
367
|
+
const value = { ...current, ...input.updates };
|
|
368
|
+
const envelope = { workspaceId: input.workspaceId, collection: input.collection, entityId: input.entityId, value, updatedAt: Date.now() };
|
|
369
|
+
const result = await this.db.update(`${ENTITY_COLLECTION}:${recordId(input.workspaceId, input.collection, input.entityId)}`, JSON.stringify(envelope));
|
|
370
|
+
if (!result.success)
|
|
371
|
+
throw new Error(`Workspace update failed: ${result.error}`);
|
|
372
|
+
await this.appendEvent(input, 'updated', value);
|
|
373
|
+
}
|
|
374
|
+
subscribe(workspaceId, handler) {
|
|
375
|
+
let stopped = false;
|
|
376
|
+
const subscribedAt = Date.now();
|
|
377
|
+
const unsubscribe = this.db.subscribe_changes(collection => {
|
|
378
|
+
if (collection !== EVENT_COLLECTION || stopped)
|
|
379
|
+
return;
|
|
380
|
+
void this.deliverEvents(workspaceId, subscribedAt, handler);
|
|
381
|
+
});
|
|
382
|
+
return () => { stopped = true; unsubscribe(); };
|
|
383
|
+
}
|
|
384
|
+
async appendEvent(input, type, value) {
|
|
385
|
+
const event = { id: generateEventId(), ...input, type, value, timestamp: Date.now() };
|
|
386
|
+
const result = await this.db.insert(`${EVENT_COLLECTION}:${event.id}`, JSON.stringify(event));
|
|
387
|
+
if (!result.success)
|
|
388
|
+
throw new Error(`Workspace event persistence failed: ${result.error}`);
|
|
389
|
+
}
|
|
390
|
+
async deliverEvents(workspaceId, subscribedAt, handler) {
|
|
391
|
+
for (const event of await this.readCollection(EVENT_COLLECTION)) {
|
|
392
|
+
if (event.workspaceId !== workspaceId || event.timestamp < subscribedAt || this.seenEvents.has(event.id))
|
|
393
|
+
continue;
|
|
394
|
+
this.seenEvents.add(event.id);
|
|
395
|
+
handler(event);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
async readCollection(collection) {
|
|
399
|
+
const result = await this.db.query(collection);
|
|
400
|
+
if (!result.success)
|
|
401
|
+
throw new Error(`Workspace query failed: ${result.error}`);
|
|
402
|
+
return result.data ? JSON.parse(result.data) : [];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function recordId(...parts) {
|
|
406
|
+
const value = parts.join('\u0000');
|
|
407
|
+
const hash = (seed) => {
|
|
408
|
+
let current = seed;
|
|
409
|
+
for (const byte of new TextEncoder().encode(value)) {
|
|
410
|
+
current ^= BigInt(byte);
|
|
411
|
+
current = BigInt.asUintN(64, current * 0x100000001b3n);
|
|
412
|
+
}
|
|
413
|
+
return current.toString(16).padStart(16, '0');
|
|
414
|
+
};
|
|
415
|
+
return `workspace_${hash(0xcbf29ce484222325n)}${hash(0x84222325cbf29ce4n)}`;
|
|
416
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feltdb/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "FeltDB Core - Application-facing database with Browser, Local, and Server runtimes. Durable state, reactive APIs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "rm -rf dist && tsc && node ../../tools/stage-core-wasm.mjs && npm run build --workspace @feltdb/react && npm run build --workspace @feltdb/migration-sherpa && npm run build --workspace @feltdb/studio && npm run build --workspace @feltdb/cli && npm run build --workspace create-feltdb && node ../../tools/assemble-core-sdk.mjs",
|
|
58
58
|
"test": "node ../../test-runner.ts",
|
|
59
|
+
"test:workspace-e2e": "node --test test/workspace-connection.e2e.test.mjs",
|
|
59
60
|
"type-check": "tsc --noEmit"
|
|
60
61
|
},
|
|
61
62
|
"keywords": [
|