@ai-matrx/alchemy 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/README.md +2 -0
- package/dist/actions.cjs +1 -1
- package/dist/actions.cjs.map +1 -1
- package/dist/actions.d.cts +192 -6
- package/dist/actions.d.ts +192 -6
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +159 -16
- package/dist/core.d.ts +159 -16
- package/dist/core.js +2 -2
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +159 -16
- package/dist/index.d.ts +159 -16
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/menu.d.cts +169 -3
- package/dist/menu.d.ts +169 -3
- package/dist/operate-server.d.cts +5 -1
- package/dist/operate-server.d.ts +5 -1
- package/dist/operate.cjs +1 -1
- package/dist/operate.cjs.map +1 -1
- package/dist/operate.d.cts +159 -16
- package/dist/operate.d.ts +159 -16
- package/dist/operate.js +2 -2
- package/dist/operate.js.map +1 -1
- package/dist/ports.cjs.map +1 -1
- package/dist/ports.d.cts +170 -4
- package/dist/ports.d.ts +170 -4
- package/dist/react-host.d.cts +169 -3
- package/dist/react-host.d.ts +169 -3
- package/dist/react-overflow.d.cts +169 -3
- package/dist/react-overflow.d.ts +169 -3
- package/dist/surface.cjs +2 -0
- package/dist/surface.cjs.map +1 -0
- package/dist/surface.d.cts +1045 -0
- package/dist/surface.d.ts +1045 -0
- package/dist/surface.js +2 -0
- package/dist/surface.js.map +1 -0
- package/package.json +13 -3
package/dist/react-overflow.d.ts
CHANGED
|
@@ -251,6 +251,148 @@ interface ClickTarget {
|
|
|
251
251
|
host?: unknown;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Operate — the format and delivery contract (Matrx Alchemy CONTRACT §2.3, ALC-16).
|
|
256
|
+
*
|
|
257
|
+
* A format is an ADAPTER: `supports` is synchronous and loads nothing; `load` dynamically
|
|
258
|
+
* imports the engine the first time the format is chosen (print for rich-html/html/pdf/docx/
|
|
259
|
+
* epub, SheetJS for xlsx). Delivery accepts only a SEALED artifact, so the bytes previewed are
|
|
260
|
+
* the bytes copied, downloaded or sent.
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
/** A reference to a declared write target (resolved by the one write door, ALC-17). */
|
|
264
|
+
interface WriteTargetRef {
|
|
265
|
+
surfaceName?: string;
|
|
266
|
+
target: string;
|
|
267
|
+
item?: {
|
|
268
|
+
itemType: string;
|
|
269
|
+
identity: Record<string, string>;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Every write returns one (CONTRACT §2.3; the door is `createWriteDoor`, ALC-17). An applied
|
|
274
|
+
* receipt may carry a `warning` with its `fix` (rule 10: a person's kind mismatch warns, never refuses).
|
|
275
|
+
* A refusal's `reason` is a `WriteRefusalReason` (`./door`).
|
|
276
|
+
*/
|
|
277
|
+
type Receipt = {
|
|
278
|
+
status: "applied";
|
|
279
|
+
to: WriteTargetRef;
|
|
280
|
+
sentence: string;
|
|
281
|
+
warning?: string;
|
|
282
|
+
fix?: string;
|
|
283
|
+
} | {
|
|
284
|
+
status: "queued";
|
|
285
|
+
to: WriteTargetRef;
|
|
286
|
+
sentence: string;
|
|
287
|
+
remedy: string;
|
|
288
|
+
} | {
|
|
289
|
+
status: "refused";
|
|
290
|
+
to: WriteTargetRef;
|
|
291
|
+
reason: string;
|
|
292
|
+
sentence: string;
|
|
293
|
+
remedy: string;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* THE ONE WRITE DOOR (Matrx Alchemy ALC-17; Applets CONTRACTS §6 "receipts through the one write door").
|
|
298
|
+
*
|
|
299
|
+
* Every write — a person's edit, a menu row, a destination send, an agent, an applet, an automation,
|
|
300
|
+
* an Action projected from a write target — lands through `door.write`. The door:
|
|
301
|
+
*
|
|
302
|
+
* 1. resolves the DECLARED write target (the surface's own, then its ancestors'); an undeclared
|
|
303
|
+
* target is refused by name;
|
|
304
|
+
* 2. enforces the mode: `stream` takes ops from the target's `streamOps`; ops on any other target
|
|
305
|
+
* need `patchable` (+ `updatesValue`); a value on a `stream` target is refused;
|
|
306
|
+
* 3. checks the kind (rule 10): a person's mismatch WARNS (the receipt is still applied, with a
|
|
307
|
+
* `warning` and a `fix`); an agent's, applet's or automation's malformed write is REFUSED;
|
|
308
|
+
* 4. applies the policy: manual → a person only; ask → a person's own act is the approval, anyone
|
|
309
|
+
* else asks through `approvals`; queued → filed through `review`; auto → applies;
|
|
310
|
+
* 5. applies through the handler: the mounted page's LIVE handler wins over the HEADLESS one;
|
|
311
|
+
* neither → refused `unapplicable` ("open <surface> to apply it");
|
|
312
|
+
* 6. turns stale / missing record / broken protected span into "cannot apply" with a one-click
|
|
313
|
+
* remedy (rule 11).
|
|
314
|
+
*
|
|
315
|
+
* Every outcome is a `Receipt` carrying the system's own sentence. `write` never throws.
|
|
316
|
+
*
|
|
317
|
+
* Who counts as a person: `person`, `menu` and `destination` (a destination send is a person's own
|
|
318
|
+
* click on "Send to …"). `agent`, `applet` and `automation` are not.
|
|
319
|
+
*
|
|
320
|
+
* Open-risk ruling — stream ops into an entity target: an entity write is ONE atomic save. Ops reach
|
|
321
|
+
* an entity target only when it is declared `patchable` (the ops are handed to the handler in one
|
|
322
|
+
* call and commit as one save); a non-patchable entity target refuses ops with the remedy "stream
|
|
323
|
+
* into the editor, then save". Op-by-op persistence into a record does not exist.
|
|
324
|
+
*/
|
|
325
|
+
|
|
326
|
+
/** Who is writing. `menu` and `destination` are a person's own act. */
|
|
327
|
+
type WriteCaller = "person" | "agent" | "applet" | "automation" | "destination" | "menu";
|
|
328
|
+
/** One text op for a `stream` (or `patchable`) target — the WidgetHandle op set. */
|
|
329
|
+
interface WriteOp {
|
|
330
|
+
op: StreamOp;
|
|
331
|
+
/** The text the op inserts or replaces with. */
|
|
332
|
+
text?: string;
|
|
333
|
+
/** What `replace` / `insert_before` / `insert_after` / `patch` anchor on. */
|
|
334
|
+
find?: string;
|
|
335
|
+
}
|
|
336
|
+
interface WriteRequest {
|
|
337
|
+
surfaceName: string;
|
|
338
|
+
/** A write target name; `"<itemType>.<name>"` names an item's target. */
|
|
339
|
+
target: string;
|
|
340
|
+
itemType?: string;
|
|
341
|
+
/** Which item, by its declared identity values. Required for an item target. */
|
|
342
|
+
itemIdentity?: Record<string, string>;
|
|
343
|
+
/** A whole value. Exactly one of `value` / `ops`. */
|
|
344
|
+
value?: unknown;
|
|
345
|
+
/** Text ops (stream / patchable targets). */
|
|
346
|
+
ops?: readonly WriteOp[];
|
|
347
|
+
by: WriteCaller;
|
|
348
|
+
runId?: string;
|
|
349
|
+
}
|
|
350
|
+
/** What a handler receives: the request plus the declared target it resolved to. */
|
|
351
|
+
interface WriteApplyRequest {
|
|
352
|
+
surfaceName: string;
|
|
353
|
+
/** The surface that declares the target (an ancestor when inherited). */
|
|
354
|
+
declaredOn: string;
|
|
355
|
+
target: WriteTarget;
|
|
356
|
+
item?: {
|
|
357
|
+
itemType: string;
|
|
358
|
+
identity: Record<string, string>;
|
|
359
|
+
};
|
|
360
|
+
value?: unknown;
|
|
361
|
+
ops?: readonly WriteOp[];
|
|
362
|
+
by: WriteCaller;
|
|
363
|
+
runId?: string;
|
|
364
|
+
}
|
|
365
|
+
/** Rule 11: the three "cannot apply" signals. */
|
|
366
|
+
type CannotApply = "stale" | "missing-record" | "broken-span";
|
|
367
|
+
/**
|
|
368
|
+
* A handler applies the write. Return nothing (or `{ status: "applied" }`) when it landed, or a
|
|
369
|
+
* `cannotApply` signal; THROWING an error whose `code` is a `CannotApply` signal means the same.
|
|
370
|
+
*/
|
|
371
|
+
type WriteHandlerResult = void | {
|
|
372
|
+
status: "applied";
|
|
373
|
+
sentence?: string;
|
|
374
|
+
} | {
|
|
375
|
+
status: "cannot-apply";
|
|
376
|
+
cannotApply: CannotApply;
|
|
377
|
+
sentence?: string;
|
|
378
|
+
remedy?: string;
|
|
379
|
+
};
|
|
380
|
+
type WriteHandler = (request: WriteApplyRequest, signal: AbortSignal) => WriteHandlerResult | Promise<WriteHandlerResult>;
|
|
381
|
+
/** Files a `queued` write for an organization's review. */
|
|
382
|
+
interface WriteReviewPort {
|
|
383
|
+
file(request: WriteApplyRequest): Promise<{
|
|
384
|
+
sentence?: string;
|
|
385
|
+
remedy?: string;
|
|
386
|
+
} | void>;
|
|
387
|
+
}
|
|
388
|
+
interface WriteDoor {
|
|
389
|
+
write(request: WriteRequest, signal?: AbortSignal): Promise<Receipt>;
|
|
390
|
+
/** A feature's write handler that works with no page mounted. Refuses a second one for the same target. */
|
|
391
|
+
registerHeadless(surfaceName: string, targetName: string, handler: WriteHandler): () => void;
|
|
392
|
+
/** A mounted page's handler; wins over the headless one while registered. Returns unregister. */
|
|
393
|
+
registerLive(surfaceName: string, targetName: string, handler: WriteHandler): () => void;
|
|
394
|
+
}
|
|
395
|
+
|
|
254
396
|
/**
|
|
255
397
|
* Surface Actions — the shapes (Applets CONTRACTS §6, FROZEN; exported here as a superset).
|
|
256
398
|
*
|
|
@@ -282,6 +424,8 @@ interface ActionError {
|
|
|
282
424
|
message: string;
|
|
283
425
|
retryable: boolean;
|
|
284
426
|
diagnostic?: string;
|
|
427
|
+
/** Superset: the one-click remedy a write door refusal names. */
|
|
428
|
+
remedy?: string;
|
|
285
429
|
}
|
|
286
430
|
/** CONTRACTS §0 `Result<T>`. */
|
|
287
431
|
type ActionResult<T = unknown> = {
|
|
@@ -319,6 +463,17 @@ type MandateRunRequest = ({
|
|
|
319
463
|
by: ActionCaller;
|
|
320
464
|
policy: ActionPolicy;
|
|
321
465
|
};
|
|
466
|
+
/**
|
|
467
|
+
* CONTRACTS §0/§3 `RunRef` — the serializable identity of a started mandate run. A mandate
|
|
468
|
+
* Action answers with THIS, not the run's result: the result arrives later on the event stream
|
|
469
|
+
* `run:<requestId>` (or `IntelligencePort.result(ref)`). Same fields as `@ai-matrx/agents`'s
|
|
470
|
+
* `RunRef`, declared here because alchemy sits below agents and never imports it.
|
|
471
|
+
*/
|
|
472
|
+
interface MandateRunRef {
|
|
473
|
+
requestId: string;
|
|
474
|
+
conversationId: string;
|
|
475
|
+
mandateKey: string;
|
|
476
|
+
}
|
|
322
477
|
|
|
323
478
|
/**
|
|
324
479
|
* `@ai-matrx/alchemy/ports` — the host ports (Matrx Alchemy CONTRACT §2.2).
|
|
@@ -338,7 +493,7 @@ type MandateRunRequest = ({
|
|
|
338
493
|
* PP-01a `window` (host-rendered windows for a live preparation session)
|
|
339
494
|
* PP-13a `transferKnobs` (organization default recipes)
|
|
340
495
|
*
|
|
341
|
-
*
|
|
496
|
+
* ALC-17 `door` (the one write door), `review` (queued writes)
|
|
342
497
|
*
|
|
343
498
|
* ── Absent-port semantics ───────────────────────────────────────────────────
|
|
344
499
|
*
|
|
@@ -374,6 +529,10 @@ type MandateRunRequest = ({
|
|
|
374
529
|
* approvals absent → a policy "ask" Action started by an agent, applet or automation is refused
|
|
375
530
|
* ("needs a person's approval"); a person's own click is the approval
|
|
376
531
|
* (`runs: "navigate"` goes through `overlay.navigate`; overlay absent → refused)
|
|
532
|
+
* door absent → write-target Actions dispatch to `pageActions` as before, and
|
|
533
|
+
* `Delivery.send` is refused with a remedy; bound → every such write goes
|
|
534
|
+
* through it and returns its receipt
|
|
535
|
+
* review absent → a write to a `queued` target is refused ("review isn't available here")
|
|
377
536
|
*
|
|
378
537
|
* Types only: this entry has no runtime code.
|
|
379
538
|
*/
|
|
@@ -527,13 +686,20 @@ interface AlchemyHostPorts {
|
|
|
527
686
|
pageActions?: PageActionPort;
|
|
528
687
|
/** Asks a person, in place, to approve an `ask` Action that an agent, applet or automation started. */
|
|
529
688
|
approvals?: ApprovalPort;
|
|
689
|
+
/** `createWriteDoor(...)`: every write to a declared target lands here and returns a receipt. */
|
|
690
|
+
door?: WriteDoor;
|
|
691
|
+
/** Files a write to a `queued` target for an organization's review. */
|
|
692
|
+
review?: WriteReviewPort;
|
|
530
693
|
}
|
|
531
694
|
interface ServerActionPort {
|
|
532
695
|
run(request: ServerActionRunRequest): Promise<ServerActionRunResponse>;
|
|
533
696
|
}
|
|
534
697
|
interface MandatePort {
|
|
535
|
-
/**
|
|
536
|
-
|
|
698
|
+
/**
|
|
699
|
+
* STARTS the run and resolves with its `RunRef` (CONTRACTS §3/§6) — never the run's result, which
|
|
700
|
+
* arrives later on `run:<requestId>` / `IntelligencePort.result(ref)`. Rejects with the system's sentence.
|
|
701
|
+
*/
|
|
702
|
+
run(request: MandateRunRequest): Promise<MandateRunRef>;
|
|
537
703
|
}
|
|
538
704
|
interface ApprovalRequest {
|
|
539
705
|
action: string;
|
package/dist/surface.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var surface_exports={};__export(surface_exports,{APPLET_SURFACE_PREFIX:()=>APPLET_SURFACE_PREFIX,PAGE_ACTION_STREAM:()=>PAGE_ACTION_STREAM,createSurfacePort:()=>createSurfacePort,readSurfaceChain:()=>readSurfaceChain,surfaceActionVisible:()=>surfaceActionVisible,valueStream:()=>valueStream});module.exports=__toCommonJS(surface_exports);var DEFAULT_MAX_INHERITANCE_DEPTH=3;var APPLET_CATEGORY="applet";function compact(value){return Object.fromEntries(Object.entries(value).filter(([,v])=>v!==void 0))}function surfaceActionRowToAction(row){return compact({name:row.name,category:row.category,label:row.label,description:row.description,input:row.input??void 0,output:row.output??void 0,runs:row.runs,target:row.target??void 0,triggeredBy:[...row.triggered_by],policy:row.policy,updatesValue:row.updates_value??void 0,itemType:row.item_type||void 0,sortOrder:row.sort_order,origin:compact({source:"surface-action",surfaceName:row.surface_name,surfaceId:row.surface_id,id:row.id,declaredBy:row.declared_by,codeRef:row.code_ref??void 0,organizationId:row.organization_id??void 0})})}function toActionInfo(declaration,declaredOn){return compact({name:declaration.name,category:declaration.category??APPLET_CATEGORY,label:declaration.label,description:declaration.description,runs:declaration.runs,policy:declaration.policy,triggeredBy:[...declaration.triggeredBy],input:declaration.input,output:declaration.output,declaredOn,target:declaration.target,updatesValue:declaration.updatesValue,itemType:declaration.itemType,source:declaration.origin?.source})}function resolveActionChain(chain,options={}){let maxDepth=options.maxDepth??DEFAULT_MAX_INHERITANCE_DEPTH,names=chain.map(link=>link.surfaceName),seen=new Set;for(let name of names){if(seen.has(name))throw new Error(`[actions] inheritance CYCLE detected at "${name}". Fix the surface chain: ${names.join(" \u2192 ")}`);seen.add(name)}if(chain.length-1>maxDepth)throw new Error(`[actions] inheritance chain for "${names[names.length-1]}" exceeds depth ${maxDepth}: ${names.join(" \u2192 ")}`);let byName=new Map;for(let link of chain){let own=new Set;for(let action of link.actions){if(own.has(action.name))throw new Error(`[actions] surface "${link.surfaceName}" declares Action "${action.name}" twice. Names are unique; nothing was overwritten.`);own.add(action.name),byName.set(action.name,toActionInfo(action,link.surfaceName))}}return[...byName.values()]}function asSurfaceClient(client){let c=client;if(typeof c.schema!="function")throw new Error("[alchemy/surface] the surface runtime needs a supabase-js v2 client carrying the viewer's session (it has no schema()).");return c}function readError(error,code="read_failed"){let out={code:error.code?`${code}:${error.code}`:code,message:error.message,retryable:!1};return error.details&&(out.diagnostic=error.details),out}async function read(query,shape){try{let answer=await query();return answer.error?{ok:!1,error:readError(answer.error)}:{ok:!0,data:shape(answer.data)}}catch(err){return{ok:!1,error:{code:"unreachable",message:err instanceof Error?err.message:String(err),retryable:!0}}}}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var APPLET_SURFACE_PREFIX="applets/";function fail(code,message,retryable=!1){return{ok:!1,error:{code,message,retryable}}}function surfaceActionVisible(row,organizationIds){return row.declared_by!=="database"||row.surface_name.startsWith(APPLET_SURFACE_PREFIX)?!0:typeof row.organization_id=="string"&&(organizationIds??[]).includes(row.organization_id)}async function readSurfaceChain(client,surfaceName,options={}){let db;try{db=asSurfaceClient(client)}catch(err){return fail("client_invalid",err instanceof Error?err.message:String(err))}let maxDepth=options.maxDepth??DEFAULT_MAX_INHERITANCE_DEPTH,names=[],at=surfaceName;for(;at;){if(names.includes(at))return fail("surface_cycle",`The surface chain loops at "${at}": ${[...names,at].join(" \u2192 ")}.`);if(names.length>maxDepth)return fail("surface_too_deep",`The surface chain for "${surfaceName}" is deeper than ${maxDepth}: ${[...names,at].join(" \u2192 ")}.`);let name=at,row=await read(()=>db.schema("ui").from("ui_surface").select("name, parent_surface_name").eq("name",name).is("deleted_at",null).maybeSingle(),d=>d);if(!row.ok)return row;if(!isRecord(row.data))return fail("surface_not_found",names.length===0?`The surface "${at}" does not exist yet; saving the Applet writes it (ui.save_applet_surface).`:`The surface "${names[names.length-1]}" names a parent "${at}" that does not exist.`);names.push(at);let parent=row.data.parent_surface_name;at=typeof parent=="string"&&parent?parent:null}let rows=await read(()=>db.schema("ui").from("ui_surface_action").select("*").in("surface_name",names).is("deleted_at",null).order("sort_order",{ascending:!0}),d=>Array.isArray(d)?d:[]);if(!rows.ok)return rows;let visible=rows.data.filter(r=>surfaceActionVisible(r,options.organizationIds)),chain=[...names].reverse().map(name=>({surfaceName:name,actions:visible.filter(r=>r.surface_name===name).map(surfaceActionRowToAction)}));try{return{ok:!0,data:resolveActionChain(chain,{maxDepth})}}catch(err){return fail("surface_chain",err instanceof Error?err.message:String(err))}}function fail2(code,message,retryable=!1,diagnostic){return{ok:!1,error:diagnostic?{code,message,retryable,diagnostic}:{code,message,retryable}}}function messageOf(error){return error instanceof Error&&error.message.trim()?error.message:typeof error=="string"&&error.trim()?error:"The run failed without saying why."}function newRunId(){let c=globalThis.crypto;return c?.randomUUID?c.randomUUID():`run-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function fillActionTarget(template,input){let source=input&&typeof input=="object"&&!Array.isArray(input)?input:{},missing=[];return{value:template.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(_,key)=>{let v=source[key];return v==null||v===""||typeof v=="object"?(missing.push(key),""):encodeURIComponent(String(v))}),missing}}function fillName(template,input){let filled=fillActionTarget(template,input);return{value:decodeURIComponent(filled.value),missing:filled.missing}}function toJson(value){return value===void 0?null:JSON.parse(JSON.stringify(value))}function refuseCaller(info,by){return info.triggeredBy.includes(by)?info.policy==="manual"&&by!=="person"?{code:"manual_only",message:`"${info.label}" (${info.name}) runs only when a person starts it.`,retryable:!1}:null:{code:"caller_not_allowed",message:`"${info.label}" (${info.name}) can't be started by ${CALLER_WORDS[by]}; it allows ${info.triggeredBy.join(", ")||"no one"}.`,retryable:!1}}var CALLER_WORDS={person:"a person",agent:"an agent",applet:"an applet",automation:"an automation"};function absent(info,capability){return fail2("capability_absent",`"${info.label}" can't run here: ${capability} isn't available on this page.`)}async function runSurfaceAction(info,input,by,ports,options={}){let refusal=refuseCaller(info,by);if(refusal)return{ok:!1,error:refusal};let context={runId:options.runId??newRunId(),by,viewerId:options.viewerId??null,surfaceName:info.declaredOn,policy:info.policy},capture=(error,stage)=>{try{ports.diagnostics.capture(error,{area:"actions",detail:{action:info.name,runs:info.runs,stage,runId:context.runId}})}catch{}};try{if(info.source==="write-target"&&ports.door){let receipt=await ports.door.write({surfaceName:info.declaredOn,target:info.name,...info.itemType?{itemType:info.itemType}:{},...options.itemIdentity?{itemIdentity:options.itemIdentity}:{},...options.ops?{ops:options.ops}:{value:input},by,runId:context.runId},options.signal);return receipt.status==="refused"?{ok:!1,error:{code:receipt.reason,message:receipt.sentence,retryable:receipt.reason==="failed",remedy:receipt.remedy}}:{ok:!0,data:receipt}}if(info.policy==="ask"&&by!=="person"&&info.runs!=="server"){if(!ports.approvals)return fail2("needs_approval",`"${info.label}" needs a person's approval, and there is no one to ask here.`);if(!await ports.approvals.ask({action:info.name,label:info.label,description:info.description,input:toJson(input),by,surfaceName:info.declaredOn}))return fail2("declined",`"${info.label}" was not approved, so it did not run.`)}switch(info.runs){case"server":{if(!ports.serverActions)return absent(info,"server actions");let filled=fillName(info.target??info.name,input);if(filled.missing.length)return fail2("input_missing",`"${info.label}" needs ${filled.missing.join(", ")}.`);let response=await ports.serverActions.run({name:filled.value,input:toJson(input),by,surface_name:info.declaredOn,policy:info.policy});return response.status==="refused"?fail2("refused",response.message):{ok:!0,data:response}}case"mandate":{if(!ports.mandates)return absent(info,"running a job");if(!info.target)return fail2("target_missing",`"${info.label}" names no job to run.`);let filled=fillName(info.target,input);if(filled.missing.length)return fail2("input_missing",`"${info.label}" needs ${filled.missing.join(", ")}.`);let record=input&&typeof input=="object"&&!Array.isArray(input)?input:{},variables=/\{[A-Za-z_]/.test(info.target)?record.variables&&typeof record.variables=="object"?toJson(record.variables):{}:toJson(record),userInput=typeof record.userInput=="string"?record.userInput:void 0;return{ok:!0,data:await ports.mandates.run({alias:filled.value,variables,...userInput!==void 0?{userInput}:{},by,policy:info.policy})}}case"navigate":{if(!ports.overlay)return absent(info,"navigation");let filled=fillActionTarget(info.target??"",input);if(filled.missing.length)return fail2("input_missing",`"${info.label}" needs ${filled.missing.join(", ")}.`);let to=info.target&&/^\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(info.target)?decodeURIComponent(filled.value):filled.value;return to?(ports.overlay.navigate(to),{ok:!0,data:{to}}):fail2("target_missing",`"${info.label}" names no page to open.`)}case"page":return ports.pageActions?await ports.pageActions.dispatch(info.name,input,context):absent(info,"this page's actions");default:{let runs=info.runs;return fail2("runs_unknown",`"${info.label}" runs as "${String(runs)}", which nothing here knows how to run.`)}}}catch(error){return capture(error,"run"),fail2("run_failed",messageOf(error),!0)}}var PAGE_ACTION_STREAM="actions",valueStream=name=>`value:${name}`;function clone(value){if(value===void 0)return value;let sc=globalThis.structuredClone;return sc?sc(value):JSON.parse(JSON.stringify(value))}function errorOf(err,code="surface_failed"){return{ok:!1,error:{code,message:err instanceof Error&&err.message?err.message:String(err),retryable:!1}}}var sequence=0;function defaultMint(prefix){let c=globalThis.crypto;return c?.randomUUID?`${prefix}-${c.randomUUID()}`:`${prefix}-${Date.now().toString(36)}-${(sequence++).toString(36)}`}function createSurfacePort(opts){let mint=opts.mintId??defaultMint,pending=opts.pending??new Map,parked=new Set,values=new Map,mounted=null,disposed=!1,report=(error,stage,detail={})=>{try{opts.ports.diagnostics.capture(error,{area:"actions",detail:{stage:`surface.${stage}`,...detail}})}catch{}},memberships=async()=>{if(opts.organizationIds)try{return await opts.organizationIds()}catch(err){report(err,"organizationIds");return}},read2=async name=>{let organizationIds=await memberships();return readSurfaceChain(opts.client,name,{...opts.maxDepth!==void 0?{maxDepth:opts.maxDepth}:{},...organizationIds?{organizationIds}:{}})},currentChain=async fresh=>{if(mounted&&!fresh)return{ok:!0,data:mounted.chain};let name=mounted?.name??(opts.surfaceName?await opts.surfaceName():null);if(!name)return{ok:!1,error:{code:"not_mounted",message:"No surface is mounted here yet.",retryable:!1}};let chain=await read2(name);return chain.ok&&mounted?.name===name&&(mounted.chain=chain.data),chain},awaitPageAction=runId=>disposed?Promise.resolve({ok:!1,error:{code:"host_disposed",message:"This page has closed.",retryable:!1}}):new Promise(resolve=>{parked.add(runId),pending.set(runId,resolve)}),selfRouted={dispatch(name,input,context){let waiting=awaitPageAction(context.runId),event={action:name,input,runId:context.runId,by:context.by},forget=()=>{pending.delete(context.runId),parked.delete(context.runId)},heard;try{heard=opts.emit(PAGE_ACTION_STREAM,event)}catch(err){throw forget(),err}return heard===!1?(forget(),Promise.resolve({ok:!1,error:{code:"action_unhandled",message:`No page is open to run "${name}".`,retryable:!1}})):waiting}},port={async mount(name){try{let chain=await read2(name);if(!chain.ok)return chain;if(opts.seedValues)try{let seeds=await opts.seedValues();for(let[key,v]of Object.entries(seeds))values.has(key)||values.set(key,clone(v))}catch(err){report(err,"seedValues",{surface:name})}return mounted={mountId:mint("mount"),name,chain:chain.data},{ok:!0,data:{mountId:mounted.mountId}}}catch(err){return errorOf(err)}},async unmount(mountId){mounted?.mountId===mountId&&(mounted=null)},async getValue(name){return clone(values.get(name))},async setValue(name,v){values.set(name,clone(v));try{opts.emit(valueStream(name),clone(v))}catch(err){report(err,"emit",{stream:valueStream(name)})}},async listActions(){try{let chain=await currentChain(!1);return chain.ok?clone(chain.data):(report(chain.error,"listActions"),[])}catch(err){return report(err,"listActions"),[]}},async runAction(name,input,by){let info;try{let known=await currentChain(!1);if(info=known.ok?known.data.find(a=>a.name===name):void 0,!info){let fresh=await currentChain(!0);if(!fresh.ok)return fresh;info=fresh.data.find(a=>a.name===name)}}catch(err){return errorOf(err)}if(!info)return{ok:!1,error:{code:"action_not_found",message:`This page has no action named "${name}".`,retryable:!1}};let viewerId=null;try{viewerId=opts.viewerId?await opts.viewerId():null}catch(err){report(err,"viewerId")}let ports={...opts.ports,pageActions:opts.pageActions??selfRouted},result=await runSurfaceAction(info,input,by,ports,{runId:mint("act"),viewerId});return result.ok&&info.updatesValue&&await port.setValue(info.updatesValue,result.data),result},async completeAction(runId,result){let resolve=pending.get(runId);pending.delete(runId),parked.delete(runId),resolve?.(result)},awaitPageAction,dispose(){disposed=!0;for(let runId of parked){let resolve=pending.get(runId);pending.delete(runId),resolve?.({ok:!1,error:{code:"host_disposed",message:"This page closed before the action finished.",retryable:!1}})}parked.clear(),mounted=null,values.clear()}};return port}
|
|
2
|
+
//# sourceMappingURL=surface.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/surface.ts","../src/declare/registry.ts","../src/actions/declarations.ts","../src/surface/client.ts","../src/surface/chain.ts","../src/actions/surface-run.ts","../src/surface/port.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/surface` — the one SurfacePort runtime (Applets CONTRACTS §6, owner AP-2).\n * Framework-neutral: zero React, zero `@ai-matrx/agents`, zero supabase import (the viewer's\n * client is typed structurally).\n *\n * readSurfaceChain(client, name, { maxDepth?, organizationIds? }) the chain's Actions, from the database\n * createSurfacePort(opts) mount / values / list / run / complete\n */\nexport {\n APPLET_SURFACE_PREFIX,\n readSurfaceChain,\n surfaceActionVisible,\n type ReadSurfaceChainOptions,\n} from \"./surface/chain\";\nexport {\n PAGE_ACTION_STREAM,\n createSurfacePort,\n valueStream,\n type CreateSurfacePortOptions,\n type PageActionEvent,\n type PendingPageActions,\n type SurfacePortHandle,\n type SurfacePortRunPorts,\n} from \"./surface/port\";\nexport type { SurfaceClient, SurfaceReadAnswer, SurfaceReadChain } from \"./surface/client\";\nexport type {\n ActionCaller,\n ActionContext,\n ActionInfo,\n ActionResult,\n MandateRunRef,\n SurfacePort,\n} from \"./actions/applet-types\";\n","/**\n * The declaration registry: inheritance, baseline injection, provenance and\n * group synthesis (CONTRACT §2.1 `DeclarationRegistry`). Ported verbatim in\n * behaviour from matrx-frontend `features/surfaces/manifests/registry.ts`\n * (ALC-14); the app now supplies its declarations and baselines.\n *\n * Guards are LOUD by design: an unknown parent, a cycle, a chain deeper than\n * the limit, a reserved or duplicate group key, a value naming an undeclared\n * group, or a reserved platform name throws on resolution — a build fails\n * instead of silently dropping values.\n */\nimport { declarationHash } from \"./hash\";\nimport type {\n DeclarationExtension,\n DeclarationIssue,\n DeclaredValue,\n ResolvedSurfaceDeclaration,\n ResolvedValue,\n Sensitivity,\n SurfaceDeclaration,\n ValueGroup,\n ValueProvenance,\n} from \"./types\";\nimport { validateDeclarations, type ValidateOptions } from \"./validate\";\n\nexport const RESERVED_GROUP_KEYS = {\n general: \"general\",\n baseline: \"baseline\",\n inheritedPrefix: \"inherited:\",\n} as const;\n\n/** Group sortOrder bands. Curated groups author 0–899; the rest is reserved. */\nexport const GENERAL_GROUP_ORDER = 850;\nexport const INHERITED_GROUP_ORDER_BASE = 9000;\nexport const BASELINE_GROUP_ORDER = 9900;\nexport const DEFAULT_MAX_INHERITANCE_DEPTH = 3;\n\nimport { DEFAULT_SENSITIVITY, resolveSensitivity } from \"./sensitivity\";\nexport { DEFAULT_SENSITIVITY, resolveSensitivity };\n\nexport type Resolved<D extends SurfaceDeclaration> = Omit<D, \"values\" | \"groups\"> & {\n values: readonly (D[\"values\"][number] & ResolvedValue)[];\n groups: readonly ValueGroup[];\n contentHash: string;\n};\n\nexport interface DeclarationRegistryOptions {\n /** Generic values injected into every declaration unless `skipBaselineValues`. */\n baselineValues?: readonly DeclaredValue[];\n /** Value names only the platform writes; a declaration claiming one is refused. */\n reservedValueNames?: readonly string[];\n /** Write-target names only the platform writes. */\n reservedWriteTargetNames?: readonly string[];\n maxInheritanceDepth?: number;\n}\n\nexport interface DeclarationRegistry<D extends SurfaceDeclaration> {\n /** Refuses a second declaration of the same surfaceName. */\n register(declaration: D): void;\n registerExtension(extension: DeclarationExtension<D>): void;\n extensions(): readonly DeclarationExtension<D>[];\n /** Declarations exactly as authored (inheritance unresolved, no baselines). */\n raw(): readonly D[];\n getRaw(surfaceName: string): D | undefined;\n /** Parent chain, ROOT FIRST. Unknown surfaces return []. */\n ancestry(surfaceName: string): string[];\n /** Direct children (declarations naming it in `inheritsFrom`), in declaration order. */\n children(surfaceName: string): string[];\n /** Inheritance + baseline + groups resolved; provenance kept. */\n all(): readonly Resolved<D>[];\n get(surfaceName: string): Resolved<D> | undefined;\n validate(options?: ValidateOptions): readonly DeclarationIssue[];\n}\n\nexport function createDeclarationRegistry<D extends SurfaceDeclaration>(\n options: DeclarationRegistryOptions = {},\n): DeclarationRegistry<D> {\n const baselineValues = options.baselineValues ?? [];\n const baselineNames = new Set(baselineValues.map((v) => v.name));\n const reservedValues = new Set(options.reservedValueNames ?? []);\n const reservedTargets = new Set(options.reservedWriteTargetNames ?? []);\n const maxDepth = options.maxInheritanceDepth ?? DEFAULT_MAX_INHERITANCE_DEPTH;\n const declarations: D[] = [];\n const index = new Map<string, D>();\n const extensionList: DeclarationExtension<D>[] = [];\n let resolvedCache: Resolved<D>[] | null = null;\n let resolvedIndex = new Map<string, Resolved<D>>();\n\n function ancestry(surfaceName: string): string[] {\n const chain: string[] = [];\n const seen = new Set<string>([surfaceName]);\n let current = index.get(surfaceName)?.inheritsFrom;\n while (current) {\n if (seen.has(current)) {\n throw new Error(\n `[surfaces] inheritsFrom CYCLE detected at \"${current}\" (from \"${surfaceName}\"). ` +\n `Fix the manifest chain: ${[...seen].join(\" → \")} → ${current}`,\n );\n }\n const parent = index.get(current);\n if (!parent) {\n throw new Error(\n `[surfaces] \"${surfaceName}\" inheritsFrom unknown surface \"${current}\" — ` +\n `the parent must be a registered declaration`,\n );\n }\n seen.add(current);\n chain.unshift(current);\n if (chain.length > maxDepth) {\n throw new Error(\n `[surfaces] inheritance chain for \"${surfaceName}\" exceeds depth ${maxDepth}: ` + chain.join(\" → \"),\n );\n }\n current = parent.inheritsFrom;\n }\n return chain;\n }\n\n function groupKeyFor(value: DeclaredValue, provenance: ValueProvenance): string {\n if (provenance.kind === \"own\" && value.group) return value.group;\n if (baselineNames.has(value.name)) return RESERVED_GROUP_KEYS.baseline;\n if (provenance.kind === \"inherited\") return `${RESERVED_GROUP_KEYS.inheritedPrefix}${provenance.from}`;\n if (provenance.kind === \"baseline\") return RESERVED_GROUP_KEYS.baseline;\n return RESERVED_GROUP_KEYS.general;\n }\n\n function resolve(declaration: D): Resolved<D> {\n const chain = ancestry(declaration.surfaceName);\n const lineage: { layer: D; from: string | null }[] = [\n ...chain.map((name) => {\n const layer = index.get(name);\n if (!layer) throw new Error(`[surfaces] missing inherited declaration \"${name}\"`);\n return { layer, from: name };\n }),\n { layer: declaration, from: null },\n ];\n\n const curatedKeys = new Set<string>();\n for (const group of declaration.groups ?? []) {\n if (\n group.key === RESERVED_GROUP_KEYS.general ||\n group.key === RESERVED_GROUP_KEYS.baseline ||\n group.key.startsWith(RESERVED_GROUP_KEYS.inheritedPrefix)\n ) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" declares reserved group key \"${group.key}\" — ` +\n `general/baseline/inherited:* are synthesized by the registry`,\n );\n }\n if (curatedKeys.has(group.key)) {\n throw new Error(`[surfaces] \"${declaration.surfaceName}\" declares duplicate group key \"${group.key}\"`);\n }\n curatedKeys.add(group.key);\n }\n for (const value of declaration.values) {\n if (reservedValues.has(value.name)) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" declares value \"${value.name}\" — that name is written by the platform; choose another name`,\n );\n }\n if (value.group && !curatedKeys.has(value.group)) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" value \"${value.name}\" references undeclared ` +\n `group \"${value.group}\" — declare it in the manifest's \\`groups\\``,\n );\n }\n }\n for (const target of declaration.writeTargets ?? []) {\n if (reservedTargets.has(target.name)) {\n throw new Error(\n `[surfaces] \"${declaration.surfaceName}\" declares write target \"${target.name}\" — that name is written by the platform; choose another name`,\n );\n }\n }\n\n const valuesByName = new Map<string, D[\"values\"][number] & ResolvedValue>();\n const inheritedLists = new Map<string, Map<string, unknown>>();\n const coreLists: { field: string; identity(entry: unknown): string }[] = [\n { field: \"configNamespaces\", identity: (entry) => (entry as { namespace: string }).namespace },\n {\n field: \"evidenceSources\",\n identity: (entry) => `${(entry as { kind: string }).kind}:${(entry as { idValue: string }).idValue}`,\n },\n ];\n const lists = [...coreLists, ...extensionList.flatMap((extension) => extension.inheritedLists ?? [])];\n for (const { layer, from } of lineage) {\n for (const value of layer.values) {\n const provenance: ValueProvenance = from ? { kind: \"inherited\", from } : { kind: \"own\" };\n valuesByName.set(value.name, {\n ...value,\n provenance,\n groupKey: groupKeyFor(value, provenance),\n resolvedSensitivity: resolveSensitivity(value),\n });\n }\n for (const list of lists) {\n const entries = (layer as unknown as Record<string, unknown>)[list.field];\n if (!Array.isArray(entries)) continue;\n const byIdentity = inheritedLists.get(list.field) ?? new Map<string, unknown>();\n for (const entry of entries) byIdentity.set(list.identity(entry), entry);\n inheritedLists.set(list.field, byIdentity);\n }\n }\n\n if (!declaration.skipBaselineValues) {\n for (const baseline of baselineValues) {\n if (valuesByName.has(baseline.name)) continue;\n valuesByName.set(baseline.name, {\n ...baseline,\n provenance: { kind: \"baseline\" },\n groupKey: RESERVED_GROUP_KEYS.baseline,\n resolvedSensitivity: resolveSensitivity(baseline),\n } as D[\"values\"][number] & ResolvedValue);\n }\n }\n\n const usedGroupKeys = new Set(Array.from(valuesByName.values(), (value) => value.groupKey));\n const groups: ValueGroup[] = [...(declaration.groups ?? [])];\n if (usedGroupKeys.has(RESERVED_GROUP_KEYS.general)) {\n groups.push({ key: RESERVED_GROUP_KEYS.general, label: \"General\", sortOrder: GENERAL_GROUP_ORDER });\n }\n for (let i = chain.length - 1, distance = 0; i >= 0; i -= 1, distance += 1) {\n const parentName = chain[i]!;\n const key = `${RESERVED_GROUP_KEYS.inheritedPrefix}${parentName}`;\n if (!usedGroupKeys.has(key)) continue;\n const parentLabel = index.get(parentName)?.label ?? parentName;\n groups.push({\n key,\n label: `Inherited from ${parentLabel}`,\n sortOrder: INHERITED_GROUP_ORDER_BASE + distance * 10,\n });\n }\n if (usedGroupKeys.has(RESERVED_GROUP_KEYS.baseline)) {\n groups.push({ key: RESERVED_GROUP_KEYS.baseline, label: \"Generic baselines\", sortOrder: BASELINE_GROUP_ORDER });\n }\n groups.sort((a, b) => a.sortOrder - b.sortOrder);\n\n const groupOrder = new Map(groups.map((group) => [group.key, group.sortOrder] as const));\n const values = Array.from(valuesByName.values()).sort((a, b) => {\n const ga = groupOrder.get(a.groupKey) ?? GENERAL_GROUP_ORDER;\n const gb = groupOrder.get(b.groupKey) ?? GENERAL_GROUP_ORDER;\n if (ga !== gb) return ga - gb;\n return (a.sortOrder ?? 1000) - (b.sortOrder ?? 1000);\n });\n\n const merged: Record<string, unknown> = {};\n for (const [field, byIdentity] of inheritedLists) {\n if (byIdentity.size > 0) merged[field] = Array.from(byIdentity.values());\n }\n return {\n ...declaration,\n values,\n groups,\n ...merged,\n contentHash: declarationHash(declaration),\n } as Resolved<D>;\n }\n\n function resolvedAll(): Resolved<D>[] {\n if (!resolvedCache) {\n resolvedCache = declarations.map(resolve);\n resolvedIndex = new Map(resolvedCache.map((entry) => [entry.surfaceName, entry] as const));\n }\n return resolvedCache;\n }\n\n const registry: DeclarationRegistry<D> = {\n register(declaration) {\n if (index.has(declaration.surfaceName)) {\n throw new Error(`[surfaces] \"${declaration.surfaceName}\" is declared twice — one surface, one declaration`);\n }\n declarations.push(declaration);\n index.set(declaration.surfaceName, declaration);\n resolvedCache = null;\n },\n registerExtension(extension) {\n if (extensionList.some((existing) => existing.key === extension.key)) {\n throw new Error(`[surfaces] declaration extension \"${extension.key}\" is registered twice`);\n }\n extensionList.push(extension);\n resolvedCache = null;\n },\n extensions: () => extensionList,\n raw: () => declarations,\n getRaw: (surfaceName) => index.get(surfaceName),\n ancestry,\n children: (surfaceName) =>\n declarations.filter((d) => d.inheritsFrom === surfaceName).map((d) => d.surfaceName),\n all: () => resolvedAll(),\n get(surfaceName) {\n resolvedAll();\n return resolvedIndex.get(surfaceName);\n },\n validate: (validateOptions) =>\n validateDeclarations(resolvedAll() as unknown as readonly ResolvedSurfaceDeclaration[], {\n ...validateOptions,\n extensions: [...(validateOptions?.extensions ?? []), ...(extensionList as DeclarationExtension[])],\n baselineNames: validateOptions?.baselineNames ?? [...baselineNames],\n }),\n };\n return registry;\n}\n","/**\n * Every source of an Action projects onto ONE shape (Applets CONTRACTS §6):\n * a declared write target, a client tool row, a `ui.ui_surface_action` row.\n * Pure functions, zero loss (the census in `declarations.test.ts` proves every\n * source field lands). Then the chain: a child surface's Action wins by name.\n */\nimport { DEFAULT_MAX_INHERITANCE_DEPTH } from \"../declare/registry\";\nimport type { Json, WriteTarget } from \"../declare/types\";\nimport type {\n ActionCaller,\n ActionDeclaration,\n ActionDeclaredBy,\n ActionInfo,\n ActionInput,\n ActionOrigin,\n ActionPolicy,\n ActionRuns,\n ActionWriteMode,\n} from \"./applet-types\";\n\n/** Default `category` of an Action that names none. */\nexport const APPLET_CATEGORY = \"applet\";\n\n/** The DB default of `ui.ui_surface_action.triggered_by`, used where a source carries no list. */\nexport const DEFAULT_TRIGGERED_BY: readonly ActionCaller[] = [\"person\", \"agent\", \"applet\"];\n\nexport const ACTION_CALLERS: readonly ActionCaller[] = [\"person\", \"agent\", \"applet\", \"automation\"];\nexport const ACTION_RUNS: readonly ActionRuns[] = [\"page\", \"server\", \"mandate\", \"navigate\"];\nexport const ACTION_POLICIES: readonly ActionPolicy[] = [\"ask\", \"auto\", \"manual\"];\n\n/** A `ui.ui_surface_client_tool` row (live columns that carry meaning). */\nexport interface ClientToolRow {\n id?: string;\n surface_name: string;\n name: string;\n label: string;\n description: string;\n input_schema: Json;\n /** Live values: \"ui\" (applied directly) | \"draft\" (proposed for review). */\n mode: \"ui\" | \"draft\";\n declared_by?: ActionDeclaredBy;\n}\n\n/** A `ui.ui_surface_action` row. */\nexport interface SurfaceActionRow {\n id?: string;\n surface_id: string;\n surface_name: string;\n /** '' = the screen itself. */\n item_type: string;\n name: string;\n category: string;\n label: string;\n description: string;\n input: ActionInput | null;\n output: string | null;\n runs: ActionRuns;\n target: string | null;\n triggered_by: ActionCaller[];\n policy: ActionPolicy;\n updates_value: string | null;\n code_ref: string | null;\n declared_by: ActionDeclaredBy;\n sort_order: number;\n /**\n * The row's organization. A `declared_by='database'` row on a surface outside `applets/` is that\n * organization's EXTENSION and applies only to its members (`readSurfaceChain`, aidream `visible_actions`).\n */\n organization_id?: string | null;\n}\n\ntype Loose<T> = { [K in keyof T]: T[K] | undefined };\n\n/** Drop undefined keys (exactOptionalPropertyTypes: an absent field is absent, never `undefined`). */\nfunction compact<T extends object>(value: Loose<T>): T {\n return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined)) as T;\n}\n\nconst POLICY_OF_APPLY: Record<NonNullable<WriteTarget[\"applyPolicy\"]>, ActionPolicy> = {\n manual: \"manual\",\n ask: \"ask\",\n auto: \"auto\",\n // Filed for an organization's review: never applied without someone saying yes.\n queued: \"ask\",\n};\n\n/** A declared write target → an Action that runs on the page. */\nexport function writeTargetToAction(target: WriteTarget): ActionDeclaration {\n const applyPolicy = target.applyPolicy ?? \"manual\";\n return compact<ActionDeclaration>({\n name: target.name,\n label: target.label,\n description: target.description,\n input: target.valueKind ?? { jsonSchema: target.valueType === \"document\" ? {} : { type: target.valueType } },\n runs: \"page\",\n triggeredBy: [...DEFAULT_TRIGGERED_BY],\n policy: POLICY_OF_APPLY[applyPolicy],\n updatesValue: target.updatesValue,\n mode: target.mode as ActionWriteMode,\n patchable: target.patchable,\n approvalComparison: target.approvalComparison,\n streamOps: target.streamOps ? [...target.streamOps] : undefined,\n destination: target.destination,\n groupKey: target.group,\n itemType: target.itemType,\n applyPolicy: target.applyPolicy,\n valueType: target.valueType,\n valueKind: target.valueKind,\n sortOrder: target.sortOrder,\n origin: { source: \"write-target\", declaredBy: \"code\" },\n });\n}\n\n/** A client tool row → an Action an agent runs on the page (\"draft\" tools are proposed first). */\nexport function clientToolToAction(row: ClientToolRow): ActionDeclaration {\n return compact<ActionDeclaration>({\n name: row.name,\n label: row.label,\n description: row.description,\n input: { jsonSchema: (row.input_schema ?? {}) as object },\n runs: \"page\",\n triggeredBy: [\"agent\"],\n policy: row.mode === \"draft\" ? \"ask\" : \"auto\",\n mode: row.mode,\n origin: compact<ActionOrigin>({ source: \"client-tool\", surfaceName: row.surface_name, id: row.id, declaredBy: row.declared_by }),\n });\n}\n\n/** A `ui.ui_surface_action` row → its Action. */\nexport function surfaceActionRowToAction(row: SurfaceActionRow): ActionDeclaration {\n return compact<ActionDeclaration>({\n name: row.name,\n category: row.category,\n label: row.label,\n description: row.description,\n input: row.input ?? undefined,\n output: row.output ?? undefined,\n runs: row.runs,\n target: row.target ?? undefined,\n triggeredBy: [...row.triggered_by],\n policy: row.policy,\n updatesValue: row.updates_value ?? undefined,\n itemType: row.item_type || undefined,\n sortOrder: row.sort_order,\n origin: compact<ActionOrigin>({\n source: \"surface-action\",\n surfaceName: row.surface_name,\n surfaceId: row.surface_id,\n id: row.id,\n declaredBy: row.declared_by,\n codeRef: row.code_ref ?? undefined,\n organizationId: row.organization_id ?? undefined,\n }),\n });\n}\n\n/** JSON-only view of an Action as declared on `declaredOn`. */\nexport function toActionInfo(declaration: ActionDeclaration, declaredOn: string): ActionInfo {\n return compact<ActionInfo>({\n name: declaration.name,\n category: declaration.category ?? APPLET_CATEGORY,\n label: declaration.label,\n description: declaration.description,\n runs: declaration.runs,\n policy: declaration.policy,\n triggeredBy: [...declaration.triggeredBy],\n input: declaration.input,\n output: declaration.output,\n declaredOn,\n target: declaration.target,\n updatesValue: declaration.updatesValue,\n itemType: declaration.itemType,\n source: declaration.origin?.source,\n });\n}\n\nexport interface ActionChainLink {\n surfaceName: string;\n actions: readonly ActionDeclaration[];\n}\n\n/**\n * The Actions a mount sees: its own plus every ancestor's, a child winning by\n * name. `chain` runs MOST GENERAL FIRST (root parent … the mounted surface),\n * as `DeclarationRegistry` resolves inheritance. Guards are loud, like the\n * declaration registry's: a surface twice in the chain is a cycle, more\n * ancestors than `maxDepth` throws, and one surface naming an Action twice throws.\n */\nexport function resolveActionChain(\n chain: readonly ActionChainLink[],\n options: { maxDepth?: number } = {},\n): ActionInfo[] {\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_INHERITANCE_DEPTH;\n const names = chain.map((link) => link.surfaceName);\n const seen = new Set<string>();\n for (const name of names) {\n if (seen.has(name)) {\n throw new Error(`[actions] inheritance CYCLE detected at \"${name}\". Fix the surface chain: ${names.join(\" → \")}`);\n }\n seen.add(name);\n }\n if (chain.length - 1 > maxDepth) {\n throw new Error(\n `[actions] inheritance chain for \"${names[names.length - 1]}\" exceeds depth ${maxDepth}: ${names.join(\" → \")}`,\n );\n }\n const byName = new Map<string, ActionInfo>();\n for (const link of chain) {\n const own = new Set<string>();\n for (const action of link.actions) {\n if (own.has(action.name)) {\n throw new Error(\n `[actions] surface \"${link.surfaceName}\" declares Action \"${action.name}\" twice. Names are unique; nothing was overwritten.`,\n );\n }\n own.add(action.name);\n byName.set(action.name, toActionInfo(action, link.surfaceName));\n }\n }\n return [...byName.values()];\n}\n","/**\n * The few reads the surface runtime makes through the VIEWER's supabase client, typed STRUCTURALLY.\n *\n * Alchemy never imports supabase or the host (package rule 13). Deliberately not\n * `SupabaseClient<Database>` either: a generated `Database` type makes `schema().from().select()`\n * enormous and a host passing its typed client hits TS2589. The host hands its client in as an\n * `object`; the ONE cast lives in `asSurfaceClient`, and every read names its schema out loud.\n *\n * Holds no key and opens no connection: the client carries the person's session, so row security\n * decides every answer.\n */\nimport type { ActionError, ActionResult } from \"../actions/applet-types\";\n\n/** What a supabase-js read resolves with. */\nexport interface SurfaceReadAnswer {\n data: unknown;\n error: { message: string; code?: string; details?: string; hint?: string } | null;\n}\n\n/** The filter chain the reads use — a subset of supabase-js's `PostgrestFilterBuilder`. */\nexport interface SurfaceReadChain extends PromiseLike<SurfaceReadAnswer> {\n eq(column: string, value: unknown): SurfaceReadChain;\n in(column: string, values: readonly unknown[]): SurfaceReadChain;\n is(column: string, value: null): SurfaceReadChain;\n order(column: string, options?: { ascending?: boolean }): SurfaceReadChain;\n maybeSingle(): PromiseLike<SurfaceReadAnswer>;\n}\n\n/** The part of a supabase-js v2 client the surface runtime reads through. */\nexport interface SurfaceClient {\n schema(name: string): { from(table: string): { select(columns: string): SurfaceReadChain } };\n}\n\n/** Bind the host's client. A value without `schema()` is refused by name. */\nexport function asSurfaceClient(client: object): SurfaceClient {\n // The one cast: the host's typed client is passed as `object` (see above) and checked here.\n const c = client as Partial<SurfaceClient>;\n if (typeof c.schema !== \"function\") {\n throw new Error(\"[alchemy/surface] the surface runtime needs a supabase-js v2 client carrying the viewer's session (it has no schema()).\");\n }\n return c as SurfaceClient;\n}\n\n/** A read's error: the database's own sentence, never paraphrased. */\nexport function readError(error: NonNullable<SurfaceReadAnswer[\"error\"]>, code = \"read_failed\"): ActionError {\n const out: ActionError = { code: error.code ? `${code}:${error.code}` : code, message: error.message, retryable: false };\n if (error.details) out.diagnostic = error.details;\n return out;\n}\n\n/** Run a read (built inside the guard); a thrown transport error answers `unreachable` (retryable), never throws. */\nexport async function read<T>(query: () => PromiseLike<SurfaceReadAnswer>, shape: (data: unknown) => T): Promise<ActionResult<T>> {\n try {\n const answer = await query();\n if (answer.error) return { ok: false, error: readError(answer.error) };\n return { ok: true, data: shape(answer.data) };\n } catch (err) {\n return { ok: false, error: { code: \"unreachable\", message: err instanceof Error ? err.message : String(err), retryable: true } };\n }\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","/**\n * `readSurfaceChain` — the Actions a surface offers, read from the DATABASE (Applets CONTRACTS §6).\n *\n * Walks `ui.ui_surface` by `parent_surface_name` (live rows only), reads every surface's\n * `ui.ui_surface_action` rows for the whole chain in ONE query, projects each row with\n * `surfaceActionRowToAction` and resolves the chain with `resolveActionChain` (a child's Action\n * wins by name). Loud, named refusals for a cycle, a chain too deep, and a missing surface.\n *\n * Organization scoping — the same rule as aidream's `visible_actions`: a `declared_by='database'`\n * row on a surface OUTSIDE `applets/` is one organization's EXTENSION and is kept only when its\n * `organization_id` is one of the viewer's memberships (`organizationIds` = ALL of them; the active\n * organization is never a filter). No `organizationIds` = extensions are dropped (fail closed).\n * Code rows and `applets/*` rows are always kept. This scopes WHICH extension applies; row\n * security still decides what the client can read at all.\n *\n * The client is the viewer's supabase-js v2 client, typed STRUCTURALLY (`./client.ts`): the package\n * never imports supabase or the host. Never throws: a transport failure answers `unreachable`\n * (retryable); a database error keeps the database's own sentence.\n */\nimport { DEFAULT_MAX_INHERITANCE_DEPTH } from \"../declare/registry\";\nimport type { ActionInfo, ActionResult } from \"../actions/applet-types\";\nimport { resolveActionChain, surfaceActionRowToAction, type ActionChainLink, type SurfaceActionRow } from \"../actions/declarations\";\nimport { asSurfaceClient, isRecord, read, type SurfaceClient } from \"./client\";\n\n/** Surfaces under this prefix belong to one Applet; their database rows are never \"extensions\". */\nexport const APPLET_SURFACE_PREFIX = \"applets/\";\n\nexport interface ReadSurfaceChainOptions {\n /** Most ancestors a surface may have (alchemy's declaration default when absent). */\n maxDepth?: number;\n /** ALL of the viewer's organization memberships. Absent = organization extensions are dropped. */\n organizationIds?: readonly string[];\n}\n\nfunction fail(code: string, message: string, retryable = false): { ok: false; error: { code: string; message: string; retryable: boolean } } {\n return { ok: false, error: { code, message, retryable } };\n}\n\n/** Whether a row applies to a viewer with these memberships (aidream `visible_actions`). */\nexport function surfaceActionVisible(row: Pick<SurfaceActionRow, \"declared_by\" | \"surface_name\" | \"organization_id\">, organizationIds: readonly string[] | undefined): boolean {\n if (row.declared_by !== \"database\") return true;\n if (row.surface_name.startsWith(APPLET_SURFACE_PREFIX)) return true;\n return typeof row.organization_id === \"string\" && (organizationIds ?? []).includes(row.organization_id);\n}\n\nexport async function readSurfaceChain(\n client: object,\n surfaceName: string,\n options: ReadSurfaceChainOptions = {},\n): Promise<ActionResult<ActionInfo[]>> {\n let db: SurfaceClient;\n try {\n db = asSurfaceClient(client);\n } catch (err) {\n return fail(\"client_invalid\", err instanceof Error ? err.message : String(err));\n }\n const maxDepth = options.maxDepth ?? DEFAULT_MAX_INHERITANCE_DEPTH;\n const names: string[] = [];\n let at: string | null = surfaceName;\n while (at) {\n if (names.includes(at)) return fail(\"surface_cycle\", `The surface chain loops at \"${at}\": ${[...names, at].join(\" → \")}.`);\n if (names.length > maxDepth) {\n return fail(\"surface_too_deep\", `The surface chain for \"${surfaceName}\" is deeper than ${maxDepth}: ${[...names, at].join(\" → \")}.`);\n }\n const name: string = at;\n const row: ActionResult<unknown> = await read(\n () => db.schema(\"ui\").from(\"ui_surface\").select(\"name, parent_surface_name\").eq(\"name\", name).is(\"deleted_at\", null).maybeSingle(),\n (d) => d,\n );\n if (!row.ok) return row;\n if (!isRecord(row.data)) {\n return fail(\n \"surface_not_found\",\n names.length === 0\n ? `The surface \"${at}\" does not exist yet; saving the Applet writes it (ui.save_applet_surface).`\n : `The surface \"${names[names.length - 1]}\" names a parent \"${at}\" that does not exist.`,\n );\n }\n names.push(at);\n const parent: unknown = row.data.parent_surface_name;\n at = typeof parent === \"string\" && parent ? parent : null;\n }\n const rows = await read(\n () =>\n db\n .schema(\"ui\")\n .from(\"ui_surface_action\")\n .select(\"*\")\n .in(\"surface_name\", names)\n .is(\"deleted_at\", null)\n .order(\"sort_order\", { ascending: true }),\n (d) => (Array.isArray(d) ? (d as SurfaceActionRow[]) : []),\n );\n if (!rows.ok) return rows;\n const visible = rows.data.filter((r) => surfaceActionVisible(r, options.organizationIds));\n // Most general first (root parent … the surface itself), as resolveActionChain expects.\n const chain: ActionChainLink[] = [...names].reverse().map((name) => ({\n surfaceName: name,\n actions: visible.filter((r) => r.surface_name === name).map(surfaceActionRowToAction),\n }));\n try {\n return { ok: true, data: resolveActionChain(chain, { maxDepth }) };\n } catch (err) {\n return fail(\"surface_chain\", err instanceof Error ? err.message : String(err));\n }\n}\n","/**\n * THE ONE RUNNER for surface Actions (Applets CONTRACTS §6). Every caller — a\n * person's click, an agent, an applet, an automation — runs an Action through\n * here, so policy and caller rules live once.\n *\n * Policy \"ask\": a person's own click is the approval. Started by an agent, applet or automation,\n * a \"server\" run carries the policy to aidream (which answers with a proposal); every other run\n * asks the person through `ports.approvals` first, and is refused by name without that port.\n *\n * Dispatch by `runs`:\n * \"server\" → `ports.serverActions.run({ name: target, input, by, surface_name, policy })`\n * \"mandate\" → `ports.mandates.run({ alias: target, variables, by, policy })` — answers with the\n * started run's `MandateRunRef`; the result streams later on `run:<requestId>`\n * \"navigate\" → `ports.overlay.navigate(target)` with `{param}` filled from the input\n * \"page\" → `ports.pageActions.dispatch(name, input, context)`\n * A port the host did not bind means that capability is ABSENT: the run is\n * refused with a sentence, never stubbed (ports rule).\n *\n * Write targets (ALC-17): an Action projected from a declared write target (`source: \"write-target\"`)\n * goes through `ports.door.write` when a door is bound — the door applies the target's own policy\n * (manual / ask / queued / auto) and its receipt becomes the result (`applied` / `queued` → ok with\n * the receipt; refused → an error whose code is the refusal reason and whose `remedy` is the door's).\n * Without a door it dispatches to `pageActions` as before.\n *\n * Never throws: every outcome is a `Result` whose error message is the\n * system's own sentence.\n */\nimport type { AlchemyHostPorts, Json } from \"../ports\";\nimport type { WriteOp } from \"../operate/door\";\nimport type { ActionCaller, ActionContext, ActionError, ActionInfo, ActionResult } from \"./applet-types\";\n\nexport type SurfaceActionPorts = Pick<\n AlchemyHostPorts,\n \"diagnostics\" | \"serverActions\" | \"mandates\" | \"pageActions\" | \"overlay\" | \"approvals\" | \"door\"\n>;\n\nexport interface RunSurfaceActionOptions {\n runId?: string;\n viewerId?: string | null;\n signal?: AbortSignal;\n /** Which item a write-target Action writes into (by its declared identity values). */\n itemIdentity?: Record<string, string>;\n /** Text edits for a stream or patchable write target, instead of the input as the whole value. */\n ops?: readonly WriteOp[];\n}\n\nfunction fail(code: string, message: string, retryable = false, diagnostic?: string): { ok: false; error: ActionError } {\n return { ok: false, error: diagnostic ? { code, message, retryable, diagnostic } : { code, message, retryable } };\n}\n\nfunction messageOf(error: unknown): string {\n if (error instanceof Error && error.message.trim()) return error.message;\n if (typeof error === \"string\" && error.trim()) return error;\n return \"The run failed without saying why.\";\n}\n\nfunction newRunId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n return `run-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Fill `{param}` placeholders from the input object. Returns the names it could not fill. */\nexport function fillActionTarget(template: string, input: unknown): { value: string; missing: string[] } {\n const source = input && typeof input === \"object\" && !Array.isArray(input) ? (input as Record<string, unknown>) : {};\n const missing: string[] = [];\n const value = template.replace(/\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g, (_, key: string) => {\n const v = source[key];\n if (v === undefined || v === null || v === \"\" || typeof v === \"object\") {\n missing.push(key);\n return \"\";\n }\n return encodeURIComponent(String(v));\n });\n return { value, missing };\n}\n\n/** Same as fillActionTarget, without URL-encoding (a mandate alias or server action name). */\nfunction fillName(template: string, input: unknown): { value: string; missing: string[] } {\n const filled = fillActionTarget(template, input);\n return { value: decodeURIComponent(filled.value), missing: filled.missing };\n}\n\nfunction toJson(value: unknown): Json {\n if (value === undefined) return null;\n return JSON.parse(JSON.stringify(value)) as Json;\n}\n\n/**\n * Who may run this Action, under its policy. Returns the refusal, or null.\n * \"manual\" = a person only. `triggeredBy` lists every caller allowed at all.\n */\nexport function refuseCaller(info: Pick<ActionInfo, \"name\" | \"label\" | \"policy\" | \"triggeredBy\">, by: ActionCaller): ActionError | null {\n if (!info.triggeredBy.includes(by)) {\n return {\n code: \"caller_not_allowed\",\n message: `\"${info.label}\" (${info.name}) can't be started by ${CALLER_WORDS[by]}; it allows ${info.triggeredBy.join(\", \") || \"no one\"}.`,\n retryable: false,\n };\n }\n if (info.policy === \"manual\" && by !== \"person\") {\n return {\n code: \"manual_only\",\n message: `\"${info.label}\" (${info.name}) runs only when a person starts it.`,\n retryable: false,\n };\n }\n return null;\n}\n\nconst CALLER_WORDS: Record<ActionCaller, string> = {\n person: \"a person\",\n agent: \"an agent\",\n applet: \"an applet\",\n automation: \"an automation\",\n};\n\nfunction absent(info: ActionInfo, capability: string): { ok: false; error: ActionError } {\n return fail(\"capability_absent\", `\"${info.label}\" can't run here: ${capability} isn't available on this page.`);\n}\n\nexport async function runSurfaceAction(\n info: ActionInfo,\n input: unknown,\n by: ActionCaller,\n ports: SurfaceActionPorts,\n options: RunSurfaceActionOptions = {},\n): Promise<ActionResult<unknown>> {\n const refusal = refuseCaller(info, by);\n if (refusal) return { ok: false, error: refusal };\n const context: ActionContext = {\n runId: options.runId ?? newRunId(),\n by,\n viewerId: options.viewerId ?? null,\n surfaceName: info.declaredOn,\n policy: info.policy,\n };\n const capture = (error: unknown, stage: string) => {\n try {\n ports.diagnostics.capture(error, { area: \"actions\", detail: { action: info.name, runs: info.runs, stage, runId: context.runId } });\n } catch {\n // A broken diagnostics port never turns a refusal into a throw.\n }\n };\n\n try {\n if (info.source === \"write-target\" && ports.door) {\n const receipt = await ports.door.write(\n {\n surfaceName: info.declaredOn,\n target: info.name,\n ...(info.itemType ? { itemType: info.itemType } : {}),\n ...(options.itemIdentity ? { itemIdentity: options.itemIdentity } : {}),\n ...(options.ops ? { ops: options.ops } : { value: input }),\n by,\n runId: context.runId,\n },\n options.signal,\n );\n if (receipt.status === \"refused\") {\n return { ok: false, error: { code: receipt.reason, message: receipt.sentence, retryable: receipt.reason === \"failed\", remedy: receipt.remedy } };\n }\n return { ok: true, data: receipt };\n }\n if (info.policy === \"ask\" && by !== \"person\" && info.runs !== \"server\") {\n if (!ports.approvals) {\n return fail(\"needs_approval\", `\"${info.label}\" needs a person's approval, and there is no one to ask here.`);\n }\n const approved = await ports.approvals.ask({\n action: info.name,\n label: info.label,\n description: info.description,\n input: toJson(input),\n by,\n surfaceName: info.declaredOn,\n });\n if (!approved) return fail(\"declined\", `\"${info.label}\" was not approved, so it did not run.`);\n }\n switch (info.runs) {\n case \"server\": {\n if (!ports.serverActions) return absent(info, \"server actions\");\n const filled = fillName(info.target ?? info.name, input);\n if (filled.missing.length) return fail(\"input_missing\", `\"${info.label}\" needs ${filled.missing.join(\", \")}.`);\n const response = await ports.serverActions.run({\n name: filled.value,\n input: toJson(input),\n by,\n surface_name: info.declaredOn,\n policy: info.policy,\n });\n if (response.status === \"refused\") return fail(\"refused\", response.message);\n return { ok: true, data: response };\n }\n case \"mandate\": {\n if (!ports.mandates) return absent(info, \"running a job\");\n if (!info.target) return fail(\"target_missing\", `\"${info.label}\" names no job to run.`);\n const filled = fillName(info.target, input);\n if (filled.missing.length) return fail(\"input_missing\", `\"${info.label}\" needs ${filled.missing.join(\", \")}.`);\n const record = input && typeof input === \"object\" && !Array.isArray(input) ? (input as Record<string, unknown>) : {};\n // A generic \"run a job\" Action carries { alias, variables, userInput }; a dedicated one's input IS the variables.\n const generic = /\\{[A-Za-z_]/.test(info.target);\n const variables = generic\n ? ((record.variables && typeof record.variables === \"object\" ? toJson(record.variables) : {}) as Record<string, Json>)\n : (toJson(record) as Record<string, Json>);\n const userInput = typeof record.userInput === \"string\" ? record.userInput : undefined;\n // The Action answers with the run's identity (RunRef); its result streams on `run:<requestId>`.\n const ref = await ports.mandates.run({\n alias: filled.value,\n variables,\n ...(userInput !== undefined ? { userInput } : {}),\n by,\n policy: info.policy,\n });\n return { ok: true, data: ref };\n }\n case \"navigate\": {\n if (!ports.overlay) return absent(info, \"navigation\");\n const filled = fillActionTarget(info.target ?? \"\", input);\n if (filled.missing.length) return fail(\"input_missing\", `\"${info.label}\" needs ${filled.missing.join(\", \")}.`);\n // `{to}` is a whole route: keep its slashes.\n const to = info.target && /^\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(info.target) ? decodeURIComponent(filled.value) : filled.value;\n if (!to) return fail(\"target_missing\", `\"${info.label}\" names no page to open.`);\n ports.overlay.navigate(to);\n return { ok: true, data: { to } };\n }\n case \"page\": {\n if (!ports.pageActions) return absent(info, \"this page's actions\");\n return await ports.pageActions.dispatch(info.name, input, context);\n }\n default: {\n const runs: never = info.runs;\n return fail(\"runs_unknown\", `\"${info.label}\" runs as \"${String(runs)}\", which nothing here knows how to run.`);\n }\n }\n } catch (error) {\n capture(error, \"run\");\n return fail(\"run_failed\", messageOf(error), true);\n }\n}\n","/**\n * `createSurfacePort` — the one SurfacePort runtime (Applets CONTRACTS §6 + Amendment 2.1).\n *\n * A parent surface offers every Action and value it has; a user's or organization's surface\n * extends it. This is the runtime a host binds once and hands to a frame:\n *\n * mount reads the chain from the DATABASE (`readSurfaceChain`); the frame's `parent`\n * argument names the same thing and is not trusted over it\n * get/setValue the surface's named values, cloned both ways; `setValue` emits `value:<name>`\n * listActions never throws — a refusal goes to `ports.diagnostics` and answers `[]`\n * runAction found by name in the mounted chain (or a fresh read), run through\n * `runSurfaceAction` (the one runner); an Action that `updatesValue` sets it\n * completeAction settles a pending page-Action run by its runId\n *\n * Page Actions: with `opts.pageActions` the host routes them (e.g. to the frame that declared the\n * surface) and may park the run with `awaitPageAction(runId)`. Without it the port routes them\n * itself: it emits `\"actions\"` `{ action, input, runId, by }` and waits for `completeAction`.\n * `dispose()` settles every run this port parked with `host_disposed`.\n *\n * The package never imports the host or supabase: the client is structural (`./client.ts`), and\n * every capability arrives as a port. Nothing here picks an organization.\n */\nimport type { PageActionPort } from \"../ports\";\nimport type { ActionCaller, ActionContext, ActionInfo, ActionResult, SurfacePort } from \"../actions/applet-types\";\nimport { runSurfaceAction, type SurfaceActionPorts } from \"../actions/surface-run\";\nimport { readSurfaceChain } from \"./chain\";\n\n/** The stream a self-routed page Action travels on (CONTRACTS Amendment 2.1). */\nexport const PAGE_ACTION_STREAM = \"actions\";\n/** The stream a surface value travels on. */\nexport const valueStream = (name: string): string => `value:${name}`;\n\n/** What travels on `\"actions\"`; the frame answers with `surface.completeAction(runId, result)`. */\nexport interface PageActionEvent {\n action: string;\n input: unknown;\n runId: string;\n by?: ActionCaller;\n}\n\n/** The runner's ports the host binds; page Actions are routed by `pageActions` / the port itself. */\nexport type SurfacePortRunPorts = Omit<SurfaceActionPorts, \"pageActions\">;\n\n/** One settle function per parked page-Action run. */\nexport type PendingPageActions = Map<string, (result: ActionResult<unknown>) => void>;\n\nexport interface CreateSurfacePortOptions {\n /** A supabase-js v2 client carrying the VIEWER's session. Typed `object` on purpose (see ./client.ts). */\n client: object;\n /** ALL of the viewer's memberships, for organization extensions. Absent = extensions are dropped. */\n organizationIds?: () => Promise<readonly string[]>;\n /** The viewer's user id, stamped on every run's context. */\n viewerId?: () => Promise<string | null>;\n /** The runner's capabilities. `diagnostics` is required; each absent port = that capability is absent. */\n ports: SurfacePortRunPorts;\n /** The host's own page-Action routing. Absent = the port emits `\"actions\"` and waits for `completeAction`. */\n pageActions?: PageActionPort;\n /**\n * The host's event hub: `value:<name>` on `setValue`, and `\"actions\"` for self-routed page Actions.\n * Return `false` when nobody is subscribed to the stream — a self-routed page Action is then\n * refused `action_unhandled` instead of waiting for an answer that cannot come.\n */\n emit(stream: string, payload: unknown): void | boolean;\n /** Values seeded at mount; a value already set is never overwritten. */\n seedValues?: () => Promise<Record<string, unknown>>;\n /** The surface to read when nothing is mounted yet (e.g. the Applet's own `applets/<id>`). */\n surfaceName?: () => Promise<string>;\n /** Most ancestors a surface may have. */\n maxDepth?: number;\n /** Ids for mounts (`\"mount\"`) and runs (`\"act\"`). */\n mintId?: (prefix: string) => string;\n /**\n * Share ONE map across the ports of one host tree, so a frame answering on its own host settles a\n * run another host routed to it. Absent = this port's own map.\n */\n pending?: PendingPageActions;\n}\n\nexport interface SurfacePortHandle extends SurfacePort {\n /** Park a page-Action run until `completeAction(runId, …)` (or `dispose()`) settles it. */\n awaitPageAction(runId: string): Promise<ActionResult<unknown>>;\n /** Settle every run this port parked with `host_disposed`, and forget the mount and values. */\n dispose(): void;\n}\n\nfunction clone<T>(value: T): T {\n if (value === undefined) return value;\n const sc = (globalThis as { structuredClone?: <V>(v: V) => V }).structuredClone;\n return sc ? sc(value) : (JSON.parse(JSON.stringify(value)) as T);\n}\n\nfunction errorOf(err: unknown, code = \"surface_failed\"): { ok: false; error: { code: string; message: string; retryable: boolean } } {\n return { ok: false, error: { code, message: err instanceof Error && err.message ? err.message : String(err), retryable: false } };\n}\n\nlet sequence = 0;\nfunction defaultMint(prefix: string): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n return c?.randomUUID ? `${prefix}-${c.randomUUID()}` : `${prefix}-${Date.now().toString(36)}-${(sequence++).toString(36)}`;\n}\n\nexport function createSurfacePort(opts: CreateSurfacePortOptions): SurfacePortHandle {\n const mint = opts.mintId ?? defaultMint;\n const pending: PendingPageActions = opts.pending ?? new Map();\n const parked = new Set<string>();\n const values = new Map<string, unknown>();\n let mounted: { mountId: string; name: string; chain: ActionInfo[] } | null = null;\n let disposed = false;\n\n const report = (error: unknown, stage: string, detail: Record<string, string> = {}) => {\n try {\n opts.ports.diagnostics.capture(error, { area: \"actions\", detail: { stage: `surface.${stage}`, ...detail } });\n } catch {\n // A broken diagnostics port never turns a refusal into a throw.\n }\n };\n\n const memberships = async (): Promise<readonly string[] | undefined> => {\n if (!opts.organizationIds) return undefined;\n try {\n return await opts.organizationIds();\n } catch (err) {\n // Fail closed: without memberships, organization extensions are dropped — and said so.\n report(err, \"organizationIds\");\n return undefined;\n }\n };\n\n const read = async (name: string): Promise<ActionResult<ActionInfo[]>> => {\n const organizationIds = await memberships();\n return readSurfaceChain(opts.client, name, {\n ...(opts.maxDepth !== undefined ? { maxDepth: opts.maxDepth } : {}),\n ...(organizationIds ? { organizationIds } : {}),\n });\n };\n\n /** The chain as it stands: the mount's, re-read when `fresh`; else the default surface's. */\n const currentChain = async (fresh: boolean): Promise<ActionResult<ActionInfo[]>> => {\n if (mounted && !fresh) return { ok: true, data: mounted.chain };\n const name = mounted?.name ?? (opts.surfaceName ? await opts.surfaceName() : null);\n if (!name) return { ok: false, error: { code: \"not_mounted\", message: \"No surface is mounted here yet.\", retryable: false } };\n const chain = await read(name);\n if (chain.ok && mounted?.name === name) mounted.chain = chain.data;\n return chain;\n };\n\n const awaitPageAction = (runId: string): Promise<ActionResult<unknown>> => {\n if (disposed) return Promise.resolve({ ok: false, error: { code: \"host_disposed\", message: \"This page has closed.\", retryable: false } });\n return new Promise((resolve) => {\n parked.add(runId);\n pending.set(runId, resolve);\n });\n };\n\n const selfRouted: PageActionPort = {\n dispatch(name: string, input: unknown, context: ActionContext): Promise<ActionResult<unknown>> {\n const waiting = awaitPageAction(context.runId);\n const event: PageActionEvent = { action: name, input, runId: context.runId, by: context.by };\n const forget = () => {\n pending.delete(context.runId);\n parked.delete(context.runId);\n };\n let heard: void | boolean;\n try {\n heard = opts.emit(PAGE_ACTION_STREAM, event);\n } catch (err) {\n forget();\n throw err; // the runner captures it and answers run_failed\n }\n if (heard === false) {\n forget();\n return Promise.resolve({ ok: false, error: { code: \"action_unhandled\", message: `No page is open to run \"${name}\".`, retryable: false } });\n }\n return waiting;\n },\n };\n\n const port: SurfacePortHandle = {\n async mount(name) {\n try {\n const chain = await read(name);\n if (!chain.ok) return chain;\n if (opts.seedValues) {\n try {\n const seeds = await opts.seedValues();\n for (const [key, v] of Object.entries(seeds)) if (!values.has(key)) values.set(key, clone(v));\n } catch (err) {\n report(err, \"seedValues\", { surface: name });\n }\n }\n mounted = { mountId: mint(\"mount\"), name, chain: chain.data };\n return { ok: true, data: { mountId: mounted.mountId } };\n } catch (err) {\n return errorOf(err);\n }\n },\n async unmount(mountId) {\n if (mounted?.mountId === mountId) mounted = null;\n },\n async getValue(name) {\n return clone(values.get(name));\n },\n async setValue(name, v) {\n values.set(name, clone(v));\n try {\n opts.emit(valueStream(name), clone(v));\n } catch (err) {\n report(err, \"emit\", { stream: valueStream(name) });\n }\n },\n async listActions() {\n try {\n const chain = await currentChain(false);\n if (!chain.ok) {\n report(chain.error, \"listActions\");\n return [];\n }\n return clone(chain.data);\n } catch (err) {\n report(err, \"listActions\");\n return [];\n }\n },\n async runAction(name, input, by) {\n let info: ActionInfo | undefined;\n try {\n const known = await currentChain(false);\n info = known.ok ? known.data.find((a) => a.name === name) : undefined;\n if (!info) {\n // Not in the mounted chain: the database may have gained it since the mount.\n const fresh = await currentChain(true);\n if (!fresh.ok) return fresh;\n info = fresh.data.find((a) => a.name === name);\n }\n } catch (err) {\n return errorOf(err);\n }\n if (!info) return { ok: false, error: { code: \"action_not_found\", message: `This page has no action named \"${name}\".`, retryable: false } };\n let viewerId: string | null = null;\n try {\n viewerId = opts.viewerId ? await opts.viewerId() : null;\n } catch (err) {\n report(err, \"viewerId\");\n }\n const ports: SurfaceActionPorts = { ...opts.ports, pageActions: opts.pageActions ?? selfRouted };\n const result = await runSurfaceAction(info, input, by, ports, { runId: mint(\"act\"), viewerId });\n if (result.ok && info.updatesValue) await port.setValue(info.updatesValue, result.data);\n return result;\n },\n async completeAction(runId, result) {\n const resolve = pending.get(runId);\n pending.delete(runId);\n parked.delete(runId);\n resolve?.(result);\n },\n awaitPageAction,\n dispose() {\n disposed = true;\n for (const runId of parked) {\n const resolve = pending.get(runId);\n pending.delete(runId);\n resolve?.({ ok: false, error: { code: \"host_disposed\", message: \"This page closed before the action finished.\", retryable: false } });\n }\n parked.clear();\n mounted = null;\n values.clear();\n },\n };\n return port;\n}\n"],"mappings":"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","names":["fail","read"]}
|