@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.
@@ -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.1';
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.1';
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-LQmvJSq6.js"></script>
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://kendel.feltdb.com/api/v1/telemetry/events';
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
- private connectedAt;
105
- private connectedClients;
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;AAEvD,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;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,CA6BzC;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,CAAqD;IAC1E,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,gBAAgB,CAAsC;gBAG5D,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,0BAA0B;IAQrC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,eAAe;IAevB;;OAEG;IACH,OAAO,IAAI,UAAU,EAAE;IAIvB;;;;;;;;;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;IAiB/E;;OAEG;IACG,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAMrE;;OAEG;IACG,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAMhD;;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;IAehB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAY1B;AAgBD;;GAEG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC,GAAG,OAAO;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB"}
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
- return new DevelopmentWorkspaceConnection(workspaceId, clientId, clientType, options);
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.connectedClients = new Map();
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.connectedAt = Date.now();
144
- this.registerClient();
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.connectedClients.delete(this.clientId);
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 Array.from(this.connectedClients.values());
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
- const event = {
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
- // In full implementation, would query FeltDB backend
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
- // In full implementation, would query FeltDB backend
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
- const event = {
251
- id: generateEventId(),
254
+ await this.requireTransport().update({
252
255
  workspaceId: this.workspaceId,
253
256
  collection,
254
257
  entityId,
255
- type: 'updated',
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(collection, event) {
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.1",
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": [