@effect-agent/platform-cloudflare 0.1.0-beta.117 → 0.1.0-beta.119

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.
@@ -710,19 +710,35 @@ declare const encodeAdminResponse: (input: AdminFailed | ExplainedRecovery | Obl
710
710
  readonly message: string;
711
711
  readonly cause?: Schema.Json | undefined;
712
712
  } | {
713
- readonly _tag: "HostProtocolError";
714
- readonly message: string;
713
+ readonly _tag: "AdmissionPolicyError";
714
+ readonly reason: "occupied" | "refused" | "unavailable";
715
+ readonly code: string;
716
+ readonly cause?: import("effect-agent/failure-diagnostic").Diagnostic | undefined;
717
+ readonly stack?: string | undefined;
718
+ } | {
719
+ readonly _tag: "SettlementConflict";
720
+ readonly submissionId: string;
721
+ readonly existingOutcome: "aborted" | "completed" | "failed";
715
722
  } | {
716
723
  readonly _tag: "LedgerError";
717
724
  readonly operation: string;
718
725
  readonly message: string;
719
726
  readonly cause?: import("effect-agent/failure-diagnostic").Diagnostic | undefined;
720
727
  } | {
721
- readonly _tag: "AdmissionPolicyError";
722
- readonly reason: "occupied" | "refused" | "unavailable";
723
- readonly code: string;
724
- readonly cause?: import("effect-agent/failure-diagnostic").Diagnostic | undefined;
725
- readonly stack?: string | undefined;
728
+ readonly _tag: "ThreadStoreError";
729
+ readonly operation: string;
730
+ readonly message: string;
731
+ readonly cause?: Schema.Json | undefined;
732
+ readonly diagnostic?: {
733
+ readonly causeTag: string;
734
+ readonly operation: string;
735
+ readonly decoder?: string | undefined;
736
+ readonly issueTag?: string | undefined;
737
+ readonly sequence?: number | undefined;
738
+ } | undefined;
739
+ } | {
740
+ readonly _tag: "ThreadNotMaterialized";
741
+ readonly threadId: string;
726
742
  } | {
727
743
  readonly _tag: "AppendConflict";
728
744
  readonly threadId: string;
@@ -730,33 +746,21 @@ declare const encodeAdminResponse: (input: AdminFailed | ExplainedRecovery | Obl
730
746
  readonly reason: "batch-digest" | "record-identity" | "tail";
731
747
  readonly actualTailSequence?: number | undefined;
732
748
  readonly actualTailDigest?: string | undefined;
733
- } | {
734
- readonly _tag: "DigestError";
735
- readonly message: string;
736
- readonly cause?: Schema.Json | undefined;
737
- } | {
738
- readonly _tag: "DurableRuntimeFailpointError";
739
- readonly location: "abort:after-intent" | "approval:after-request-append" | "approval:after-suspend" | "checkpoint:after-save" | "checkpoint:before-save" | "claim:after-claim" | "compaction:after-canonical-append" | "compaction:before-canonical-append" | "input:after-canonical-append" | "join:after-canonical-append" | "join:after-claim" | "policy:after-reservation-append" | "policy:before-reservation-append" | "resolve:after-intent" | "run:after-duration-append" | "run:after-start-append" | "run:before-duration-append" | "run:before-start-append" | "step:after-step-append" | "subagent:after-admit" | "subagent:after-child-abort-intent" | "subagent:after-child-ready" | "subagent:after-join-append" | "subagent:after-release" | "subagent:after-release-pending" | "subagent:after-request-append" | "subagent:after-reserve" | "subagent:after-sibling-settle" | "subagent:after-start-append" | "subagent:after-suspend" | "subagent:before-join-append" | "submit:after-admit" | "submit:after-materialize" | "terminalize:after-canonical-append" | "terminalize:after-reserve" | "tools:after-prepared-append" | "tools:after-unavailable-append" | "tools:before-prepared-append" | "tools:before-unavailable-append" | "turn:after-canonical-append" | "turn:after-response-append" | "turn:after-results-append" | "update:after-canonical-append" | "update:after-delivery-insert" | "update:before-canonical-append" | "update:before-delivery-insert" | "worker:after-completion-append" | "worker:after-origin-append" | "worker:after-report-append" | "worker:after-report-delivery" | "worker:after-source-append" | "worker:after-stop-append" | "worker:after-stop-seal" | "worker:after-subtree-append" | "worker:before-completion-append" | "worker:before-origin-append" | "worker:before-report-append" | "worker:before-report-delivery" | "worker:before-source-append" | "worker:before-stop-append" | "worker:before-stop-seal" | "worker:before-subtree-append";
740
749
  } | {
741
750
  readonly _tag: "FenceRejected";
742
751
  readonly threadId: string;
743
752
  readonly actualEpoch: number;
744
753
  readonly attemptedEpoch: number;
745
754
  } | {
746
- readonly _tag: "ThreadNotMaterialized";
747
- readonly threadId: string;
755
+ readonly _tag: "HostProtocolError";
756
+ readonly message: string;
748
757
  } | {
749
- readonly _tag: "ThreadStoreError";
750
- readonly operation: string;
758
+ readonly _tag: "DigestError";
751
759
  readonly message: string;
752
760
  readonly cause?: Schema.Json | undefined;
753
- readonly diagnostic?: {
754
- readonly causeTag: string;
755
- readonly operation: string;
756
- readonly decoder?: string | undefined;
757
- readonly issueTag?: string | undefined;
758
- readonly sequence?: number | undefined;
759
- } | undefined;
761
+ } | {
762
+ readonly _tag: "DurableRuntimeFailpointError";
763
+ readonly location: "abort:after-intent" | "approval:after-request-append" | "approval:after-suspend" | "checkpoint:after-save" | "checkpoint:before-save" | "claim:after-claim" | "compaction:after-canonical-append" | "compaction:before-canonical-append" | "input:after-canonical-append" | "join:after-canonical-append" | "join:after-claim" | "policy:after-reservation-append" | "policy:before-reservation-append" | "resolve:after-intent" | "run:after-duration-append" | "run:after-start-append" | "run:before-duration-append" | "run:before-start-append" | "step:after-step-append" | "subagent:after-admit" | "subagent:after-child-abort-intent" | "subagent:after-child-ready" | "subagent:after-join-append" | "subagent:after-release" | "subagent:after-release-pending" | "subagent:after-request-append" | "subagent:after-reserve" | "subagent:after-sibling-settle" | "subagent:after-start-append" | "subagent:after-suspend" | "subagent:before-join-append" | "submit:after-admit" | "submit:after-materialize" | "terminalize:after-canonical-append" | "terminalize:after-reserve" | "tools:after-prepared-append" | "tools:after-unavailable-append" | "tools:before-prepared-append" | "tools:before-unavailable-append" | "turn:after-canonical-append" | "turn:after-response-append" | "turn:after-results-append" | "update:after-canonical-append" | "update:after-delivery-insert" | "update:before-canonical-append" | "update:before-delivery-insert" | "worker:after-completion-append" | "worker:after-origin-append" | "worker:after-report-append" | "worker:after-report-delivery" | "worker:after-source-append" | "worker:after-stop-append" | "worker:after-stop-seal" | "worker:after-subtree-append" | "worker:before-completion-append" | "worker:before-origin-append" | "worker:before-report-append" | "worker:before-report-delivery" | "worker:before-source-append" | "worker:before-stop-append" | "worker:before-stop-seal" | "worker:before-subtree-append";
760
764
  } | {
761
765
  readonly _tag: "OperationDenied";
762
766
  readonly operation: "abort" | "awaitSettlement" | "explain" | "observe" | "resolveApproval" | "resolveUnknown" | "retry" | "scanObligations" | "verify" | "wake";
@@ -777,10 +781,6 @@ declare const encodeAdminResponse: (input: AdminFailed | ExplainedRecovery | Obl
777
781
  readonly _tag: "OwnershipLost";
778
782
  readonly submissionId: string;
779
783
  readonly actualEpoch: number;
780
- } | {
781
- readonly _tag: "SettlementConflict";
782
- readonly submissionId: string;
783
- readonly existingOutcome: "aborted" | "completed" | "failed";
784
784
  };
785
785
  }, Schema.SchemaError, never>;
786
786
  declare const decodeAdminResponse: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Effect.Effect<AdminFailed | ExplainedRecovery | ObligationsScanned | RetryExecuted | VerifiedIntegrity, Schema.SchemaError, never>;
@@ -833,4 +833,4 @@ interface Class<EventServices = never> {
833
833
  declare const make: <ApplicationServices, ApplicationError, EventServices = never, EventLayerError = never>(applicationLayer: Layer.Layer<CloudflareDurableRuntimeServices | ApplicationServices, ApplicationError, CloudflareBootstrapServices | DurableObjectState$1.DurableObjectState | WorkerEnvironment | DurableObjectContext | ThreadObjectNamespace>, options: Options<ApplicationServices, EventServices, EventLayerError>) => Class<ApplicationServices | EventServices>;
834
834
  //#endregion
835
835
  export { ThreadPublicationOptions as A, portCall as C, CloudflareDurableRuntimeOptions as D, CloudflareDurableRuntimeInitializationError as E, layerConfig as M, layerHostConfig as N, CloudflareDurableRuntimeServices as O, layerInHost as P, make as S, CloudflareBootstrapServices as T, decodeAdminVerifyRequest as _, AdminVerifyRequest as a, encodeAdminResponse as b, Instance as c, RetryExecuted as d, ThreadObject_d_exports as f, decodeAdminResponse as g, decodeAdminExplainRequest as h, AdminResponse as i, layer as j, ThreadObjectPorts as k, ObligationsScanned as l, VerifiedIntegrity as m, AdminFailed as n, Class as o, ThreadRpcOperation as p, AdminFailure as r, ExplainedRecovery as s, AdminExplainRequest as t, Options as u, decodeObligationThresholds as v, submit as w, handleRpc as x, decodeRetryCommand as y };
836
- //# sourceMappingURL=ThreadObject-S05rNeF7.d.mts.map
836
+ //# sourceMappingURL=ThreadObject-D_prWu8-.d.mts.map
@@ -1,2 +1,2 @@
1
- import { A as ThreadPublicationOptions, C as portCall, D as CloudflareDurableRuntimeOptions, E as CloudflareDurableRuntimeInitializationError, M as layerConfig, N as layerHostConfig, O as CloudflareDurableRuntimeServices, P as layerInHost, S as make, T as CloudflareBootstrapServices, _ as decodeAdminVerifyRequest, a as AdminVerifyRequest, b as encodeAdminResponse, c as Instance, d as RetryExecuted, g as decodeAdminResponse, h as decodeAdminExplainRequest, i as AdminResponse, j as layer, k as ThreadObjectPorts, l as ObligationsScanned, m as VerifiedIntegrity, n as AdminFailed, o as Class, p as ThreadRpcOperation, r as AdminFailure, s as ExplainedRecovery, t as AdminExplainRequest, u as Options, v as decodeObligationThresholds, w as submit, x as handleRpc, y as decodeRetryCommand } from "./ThreadObject-S05rNeF7.mjs";
1
+ import { A as ThreadPublicationOptions, C as portCall, D as CloudflareDurableRuntimeOptions, E as CloudflareDurableRuntimeInitializationError, M as layerConfig, N as layerHostConfig, O as CloudflareDurableRuntimeServices, P as layerInHost, S as make, T as CloudflareBootstrapServices, _ as decodeAdminVerifyRequest, a as AdminVerifyRequest, b as encodeAdminResponse, c as Instance, d as RetryExecuted, g as decodeAdminResponse, h as decodeAdminExplainRequest, i as AdminResponse, j as layer, k as ThreadObjectPorts, l as ObligationsScanned, m as VerifiedIntegrity, n as AdminFailed, o as Class, p as ThreadRpcOperation, r as AdminFailure, s as ExplainedRecovery, t as AdminExplainRequest, u as Options, v as decodeObligationThresholds, w as submit, x as handleRpc, y as decodeRetryCommand } from "./ThreadObject-D_prWu8-.mjs";
2
2
  export { AdminExplainRequest, AdminFailed, AdminFailure, AdminResponse, AdminVerifyRequest, type CloudflareBootstrapServices as BootstrapServices, Class, ExplainedRecovery, type CloudflareDurableRuntimeInitializationError as InitializationError, Instance, ObligationsScanned, Options, type ThreadPublicationOptions as PublicationOptions, RetryExecuted, type CloudflareDurableRuntimeOptions as RuntimeOptions, type CloudflareDurableRuntimeServices as Services, ThreadObjectPorts, ThreadRpcOperation, VerifiedIntegrity, decodeAdminExplainRequest, decodeAdminResponse, decodeAdminVerifyRequest, decodeObligationThresholds, decodeRetryCommand, encodeAdminResponse, handleRpc, layer, layerConfig, layerHostConfig, layerInHost, make, portCall, submit };
package/dist/index.d.mts CHANGED
@@ -8,6 +8,6 @@ import { t as CloudflareMemory_d_exports } from "./CloudflareMemory.mjs";
8
8
  import { t as CloudflareScheduling_d_exports } from "./CloudflareScheduling.mjs";
9
9
  import { t as CloudflareSubscriptions_d_exports } from "./CloudflareSubscriptions.mjs";
10
10
  import { t as CloudflareThreadClient_d_exports } from "./CloudflareThreadClient.mjs";
11
- import { f as ThreadObject_d_exports } from "./ThreadObject-S05rNeF7.mjs";
11
+ import { f as ThreadObject_d_exports } from "./ThreadObject-D_prWu8-.mjs";
12
12
  import { t as WakeScheduler_d_exports } from "./WakeScheduler.mjs";
13
13
  export { Alarm_d_exports as Alarm, CloudflareAiGateway_d_exports as CloudflareAiGateway, CloudflareBindings_d_exports as CloudflareBindings, CloudflareBrowser_d_exports as CloudflareBrowser, CloudflareCodeMode_d_exports as CloudflareCodeMode, CloudflareConfig_d_exports as CloudflareConfig, CloudflareMemory_d_exports as CloudflareMemory, CloudflareScheduling_d_exports as CloudflareScheduling, CloudflareSubscriptions_d_exports as CloudflareSubscriptions, CloudflareThreadClient_d_exports as CloudflareThreadClient, ThreadObject_d_exports as ThreadObject, WakeScheduler_d_exports as WakeScheduler };
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@effect-agent/platform-cloudflare","version":"0.1.0-beta.117","dependencies":{"@effect-agent/storage-cloudflare":"0.1.0-beta.117","@effect/platform-browser":"4.0.0-rc.116","@effect/sql-sqlite-do":"4.0.0-rc.116","effect-agent":"0.1.0-beta.117"},"devDependencies":{"@cloudflare/puppeteer":"1.1.0","@cloudflare/vitest-pool-workers":"0.21.3","@cloudflare/workers-types":"5.20260825.1","@effect-agent/testing":"0.1.0-beta.117","@effect/platform-node":"4.0.0-rc.116","@effect/sql-d1":"4.0.0-rc.116","@effect/vitest":"4.0.0-rc.116","effect":"4.0.0-rc.116","effect-cf":"0.44.1","esbuild":"0.28.1","miniflare":"5.20260811.1-alpha","typescript":"7.0.2","vite-plus":"0.3.2","vitest":"4.1.11"},"peerDependencies":{"@cloudflare/puppeteer":"^1.1.0","effect":"^4.0.0-rc.116","effect-cf":"^0.44.1 || ^0.45.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./alarm":{"types":"./dist/Alarm.d.mts","default":"./dist/Alarm.mjs"},"./browser-rest-capture":{"types":"./dist/BrowserRestCapture.d.mts","default":"./dist/BrowserRestCapture.mjs"},"./browser-rest-crawl":{"types":"./dist/BrowserRestCrawl.d.mts","default":"./dist/BrowserRestCrawl.mjs"},"./cloudflare-bindings":{"types":"./dist/CloudflareBindings.d.mts","default":"./dist/CloudflareBindings.mjs"},"./cloudflare-browser":{"types":"./dist/CloudflareBrowser.d.mts","default":"./dist/CloudflareBrowser.mjs"},"./cloudflare-code-mode":{"types":"./dist/CloudflareCodeMode.d.mts","default":"./dist/CloudflareCodeMode.mjs"},"./cloudflare-config":{"types":"./dist/CloudflareConfig.d.mts","default":"./dist/CloudflareConfig.mjs"},"./cloudflare-memory":{"types":"./dist/CloudflareMemory.d.mts","default":"./dist/CloudflareMemory.mjs"},"./cloudflare-scheduling":{"types":"./dist/CloudflareScheduling.d.mts","default":"./dist/CloudflareScheduling.mjs"},"./cloudflare-subscriptions":{"types":"./dist/CloudflareSubscriptions.d.mts","default":"./dist/CloudflareSubscriptions.mjs"},"./cloudflare-thread-client":{"types":"./dist/CloudflareThreadClient.d.mts","default":"./dist/CloudflareThreadClient.mjs"},"./interactive-browser":{"types":"./dist/InteractiveBrowser.d.mts","default":"./dist/InteractiveBrowser.mjs"},"./protected-browser":{"types":"./dist/ProtectedBrowser.d.mts","default":"./dist/ProtectedBrowser.mjs"},"./thread-object":{"types":"./dist/ThreadObject.d.mts","default":"./dist/ThreadObject.mjs"},"./wake-scheduler":{"types":"./dist/WakeScheduler.d.mts","default":"./dist/WakeScheduler.mjs"},"./cloudflare-ai-gateway":{"types":"./dist/CloudflareAiGateway.d.mts","default":"./dist/CloudflareAiGateway.mjs"}},"description":"Cloudflare Layer assembly for Effect Agent: Durable Objects and Browser Run adapters.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/platform-cloudflare"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json"},"peerDependenciesMeta":{"@cloudflare/puppeteer":{"optional":true}}}
1
+ {"name":"@effect-agent/platform-cloudflare","version":"0.1.0-beta.119","dependencies":{"@effect-agent/storage-cloudflare":"0.1.0-beta.119","@effect/platform-browser":"4.0.0-rc.116","@effect/sql-sqlite-do":"4.0.0-rc.116","effect-agent":"0.1.0-beta.119"},"devDependencies":{"@cloudflare/puppeteer":"1.1.0","@cloudflare/vitest-pool-workers":"0.21.3","@cloudflare/workers-types":"5.20260825.1","@effect-agent/testing":"0.1.0-beta.119","@effect/platform-node":"4.0.0-rc.116","@effect/sql-d1":"4.0.0-rc.116","@effect/vitest":"4.0.0-rc.116","effect":"4.0.0-rc.116","effect-cf":"0.44.1","esbuild":"0.28.1","miniflare":"5.20260811.1-alpha","typescript":"7.0.2","vite-plus":"0.3.2","vitest":"4.1.11"},"peerDependencies":{"@cloudflare/puppeteer":"^1.1.0","effect":"^4.0.0-rc.116","effect-cf":"^0.44.1 || ^0.45.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./alarm":{"types":"./dist/Alarm.d.mts","default":"./dist/Alarm.mjs"},"./browser-rest-capture":{"types":"./dist/BrowserRestCapture.d.mts","default":"./dist/BrowserRestCapture.mjs"},"./browser-rest-crawl":{"types":"./dist/BrowserRestCrawl.d.mts","default":"./dist/BrowserRestCrawl.mjs"},"./cloudflare-bindings":{"types":"./dist/CloudflareBindings.d.mts","default":"./dist/CloudflareBindings.mjs"},"./cloudflare-browser":{"types":"./dist/CloudflareBrowser.d.mts","default":"./dist/CloudflareBrowser.mjs"},"./cloudflare-code-mode":{"types":"./dist/CloudflareCodeMode.d.mts","default":"./dist/CloudflareCodeMode.mjs"},"./cloudflare-config":{"types":"./dist/CloudflareConfig.d.mts","default":"./dist/CloudflareConfig.mjs"},"./cloudflare-memory":{"types":"./dist/CloudflareMemory.d.mts","default":"./dist/CloudflareMemory.mjs"},"./cloudflare-scheduling":{"types":"./dist/CloudflareScheduling.d.mts","default":"./dist/CloudflareScheduling.mjs"},"./cloudflare-subscriptions":{"types":"./dist/CloudflareSubscriptions.d.mts","default":"./dist/CloudflareSubscriptions.mjs"},"./cloudflare-thread-client":{"types":"./dist/CloudflareThreadClient.d.mts","default":"./dist/CloudflareThreadClient.mjs"},"./interactive-browser":{"types":"./dist/InteractiveBrowser.d.mts","default":"./dist/InteractiveBrowser.mjs"},"./protected-browser":{"types":"./dist/ProtectedBrowser.d.mts","default":"./dist/ProtectedBrowser.mjs"},"./thread-object":{"types":"./dist/ThreadObject.d.mts","default":"./dist/ThreadObject.mjs"},"./wake-scheduler":{"types":"./dist/WakeScheduler.d.mts","default":"./dist/WakeScheduler.mjs"},"./cloudflare-ai-gateway":{"types":"./dist/CloudflareAiGateway.d.mts","default":"./dist/CloudflareAiGateway.mjs"}},"description":"Cloudflare Layer assembly for Effect Agent: Durable Objects and Browser Run adapters.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/platform-cloudflare"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json"},"peerDependenciesMeta":{"@cloudflare/puppeteer":{"optional":true}}}
@@ -62,7 +62,10 @@ export interface BrowserRunProtectedSession {
62
62
  readonly getHandoffState: Effect.Effect<BrowserRunHandoffState, ProtectedBrowserError>;
63
63
  /** Read only the exact page’s current origin after its recorded handoff completes; tools remain paused. */
64
64
  readonly getReturnOrigin: Effect.Effect<typeof CredentialOrigin.Type, ProtectedBrowserError>;
65
- /** Resume a committed pause; human handoffs also require provider completion. Observe before acting. */
65
+ /**
66
+ * Resume a committed pause; human handoffs also require provider completion. Returns no page data.
67
+ * A fresh authorized observation must succeed before page actions or credential operations.
68
+ */
66
69
  readonly returnControl: Effect.Effect<void, ProtectedBrowserError>;
67
70
  /** Release this attachment only after committing its suspended checkpoint; preserve the remote browser. */
68
71
  readonly detach: Effect.Effect<void, ProtectedBrowserError>;
@@ -60,12 +60,26 @@ export const inspectFrame = `(() => {
60
60
  } else if (el instanceof HTMLButtonElement || (el instanceof HTMLInputElement && ['submit','button'].includes(type))) {
61
61
  if (!el.matches(':disabled')) role = type === 'submit' && form ? 'submit' : type === 'button' ? 'button' : 'unsupported';
62
62
  } else if (el instanceof HTMLAnchorElement) role = 'link';
63
+ const options = [];
64
+ let truncated = false;
65
+ if (role === 'select') {
66
+ for (let index = 0; index < el.options.length; index++) {
67
+ if (index === 256) { truncated = true; break; }
68
+ const option = el.options[index];
69
+ const label = option.label.trim();
70
+ // Never publish a shortened label as an exact fill choice.
71
+ if (label.length > 200) { truncated = true; continue; }
72
+ options.push({label, selected: option.selected, disabled: option.matches(':disabled')});
73
+ }
74
+ }
63
75
  const fingerprint = JSON.stringify([role, action, method, enctype, name, completion, type, choiceValue]);
64
76
  return { role, formIndex, action, fingerprint, ...(isChoice(el) ? {checked: el.checked} : {}),
77
+ ...(role === 'select' ? {options, truncated} : {}),
65
78
  label: (labelText(el) ?? (nativeField ? '' : el.textContent) ?? '').slice(0,200) };
66
79
  };
67
- const expose = ({role, formIndex, action, label, checked}) =>
68
- ({role, formIndex, action, label, ...(checked === undefined ? {} : {checked})});
80
+ const expose = ({role, formIndex, action, label, checked, options, truncated}) =>
81
+ ({role, formIndex, action, label, ...(checked === undefined ? {} : {checked}),
82
+ ...(options === undefined ? {} : {options, truncated})});
69
83
  const original = elements.map(describe);
70
84
  const validate = (index) => {
71
85
  const current = describe(elements[index]);
@@ -95,13 +109,13 @@ export const inspectFrame = `(() => {
95
109
  const current = validate(index);
96
110
  if (!current || current.role !== role) return false;
97
111
  const el = elements[index];
98
- if (role === 'select') {
112
+ if (el instanceof HTMLSelectElement) {
99
113
  const options = [...el.options].filter(option => !option.matches(':disabled'));
100
- const values = options.filter(option => option.value === value);
101
- const matches = values.length > 0 ? values : options.filter(option => option.textContent?.trim() === value);
102
- if (matches.length !== 1) return 'unsupported';
114
+ // Ordinary fills name the visible choice; credential material stays a private value.
115
+ const matches = options.filter(option => (role === 'select' ? option.label.trim() : option.value) === value);
116
+ if (matches.length !== 1) return 'unsupported-before-write';
103
117
  value = matches[0].value;
104
- if ([...el.options].filter(option => option.value === value).length !== 1) return 'unsupported';
118
+ if ([...el.options].filter(option => option.value === value).length !== 1) return 'unsupported-before-write';
105
119
  }
106
120
  let prototype = Object.getPrototypeOf(el);
107
121
  let setter;
@@ -36,9 +36,12 @@ const Description = Schema.Struct({
36
36
  action: Schema.String.check(Schema.isMaxLength(maxAttributeLength)),
37
37
  label: Schema.String.check(Schema.isMaxLength(200)),
38
38
  checked: Schema.optionalKey(Schema.Boolean),
39
+ options: ProtectedBrowserControl.fields.options,
40
+ truncated: Schema.optionalKey(Schema.Boolean),
39
41
  });
40
42
 
41
43
  const Descriptions = Schema.Array(Schema.NullOr(Description)).check(Schema.isMaxLength(65));
44
+ const FillResult = Schema.Literals([true, false, "unsupported-before-write", "unsupported"]);
42
45
 
43
46
  interface FrameState {
44
47
  readonly frame: Frame;
@@ -367,6 +370,7 @@ export const makeProtectedNativeTransport = Effect.fn("ProtectedNativeTransport.
367
370
  const desc = descriptions[index];
368
371
 
369
372
  if (!desc) continue;
373
+ if (desc.truncated) truncated = true;
370
374
  if (discovered.length === 64) {
371
375
  truncated = true;
372
376
  break;
@@ -387,6 +391,7 @@ export const makeProtectedNativeTransport = Effect.fn("ProtectedNativeTransport.
387
391
  role: desc.role,
388
392
  label: desc.label,
389
393
  ...(desc.checked === undefined ? {} : { checked: desc.checked }),
394
+ ...(desc.options === undefined ? {} : { options: desc.options }),
390
395
  ...(desc.role === "link" ? { url: desc.action } : {}),
391
396
  target: CredentialTarget.make({
392
397
  topOrigin: before.topOrigin,
@@ -439,7 +444,7 @@ export const makeProtectedNativeTransport = Effect.fn("ProtectedNativeTransport.
439
444
  // CDP dispatch may mutate before its reply is lost, so uncertainty starts here.
440
445
  yield* dispatch.mark;
441
446
 
442
- const filled = yield* remote("protected.fill", () =>
447
+ const raw = yield* remote("protected.fill", () =>
443
448
  state.frame.handle.evaluate(
444
449
  (held, index, expectedRole, secret) => {
445
450
  if (typeof held !== "object" || held === null) return false;
@@ -452,8 +457,15 @@ export const makeProtectedNativeTransport = Effect.fn("ProtectedNativeTransport.
452
457
  ),
453
458
  );
454
459
 
460
+ const filled = yield* decode(FillResult, raw);
461
+
462
+ if (filled === false || filled === "unsupported-before-write") {
463
+ yield* dispatch.confirmNoWrite;
464
+
465
+ return yield* transportError(filled === false ? "stale-reference" : "unsupported");
466
+ }
467
+
455
468
  if (filled === "unsupported") return yield* transportError("unsupported");
456
- if (filled !== true) return yield* transportError("stale-reference");
457
469
  }),
458
470
  click: Effect.fn("ProtectedNativeTransport.click")(function* (ref) {
459
471
  const state = yield* get(ref);
@@ -57,7 +57,11 @@ export class ProtectedTransportError extends Schema.TaggedError<ProtectedTranspo
57
57
  /** Per-write evidence authority, provided by the policy immediately around a transport fill. */
58
58
  export class ProtectedBrowserDispatch extends Context.Service<
59
59
  ProtectedBrowserDispatch,
60
- { readonly mark: Effect.Effect<void> }
60
+ {
61
+ readonly mark: Effect.Effect<void>;
62
+ /** Only an acknowledged reply before assignment may restore the preceding dispatch evidence. */
63
+ readonly confirmNoWrite: Effect.Effect<void>;
64
+ }
61
65
  >()("@effect-agent/platform-cloudflare/ProtectedBrowserDispatch") {}
62
66
 
63
67
  /** Decoded adapter boundary. SDK exceptions and page diagnostics never cross this port. */
@@ -404,7 +408,8 @@ export const makeProtectedBrowserPolicy = Effect.fn("ProtectedBrowser.open")(fun
404
408
  const interrupt = cause.reasons.some((reason) => reason._tag === "Interrupt");
405
409
 
406
410
  if (
407
- dispatch !== "not-dispatched" ||
411
+ dispatch === "possibly-dispatched" ||
412
+ (dispatch === "dispatched" && reason !== "busy") ||
408
413
  interrupt ||
409
414
  reason === "provider" ||
410
415
  reason === "timeout"
@@ -576,6 +581,8 @@ export const makeProtectedBrowserPolicy = Effect.fn("ProtectedBrowser.open")(fun
576
581
  target: control.target,
577
582
  role: control.role,
578
583
  });
584
+ const previousDispatch = dispatch;
585
+
579
586
  yield* publicFailure(
580
587
  driver.fill(decoded.ref, control.role, Redacted.make(decoded.value)),
581
588
  ).pipe(
@@ -583,6 +590,9 @@ export const makeProtectedBrowserPolicy = Effect.fn("ProtectedBrowser.open")(fun
583
590
  mark: Effect.sync(() => {
584
591
  dispatch = "possibly-dispatched";
585
592
  }),
593
+ confirmNoWrite: Effect.sync(() => {
594
+ dispatch = previousDispatch;
595
+ }),
586
596
  }),
587
597
  );
588
598
  dispatch = "dispatched";
@@ -725,6 +735,8 @@ export const makeProtectedBrowserPolicy = Effect.fn("ProtectedBrowser.open")(fun
725
735
  const value = secretFor(material, field.role);
726
736
 
727
737
  if (value === undefined) return yield* fail("missing-credential");
738
+ const previousDispatch = dispatch;
739
+
728
740
  observation = "protected";
729
741
  yield* publicFailure(driver.fill(field.ref, field.role, value)).pipe(
730
742
  Effect.provideService(ProtectedBrowserDispatch, {
@@ -733,6 +745,10 @@ export const makeProtectedBrowserPolicy = Effect.fn("ProtectedBrowser.open")(fun
733
745
  if (!exposures.some((target) => sameTarget(target, offer.target)))
734
746
  exposures.push(offer.target);
735
747
  }),
748
+ // A refused later field cannot erase a completed earlier field or its exposure.
749
+ confirmNoWrite: Effect.sync(() => {
750
+ dispatch = previousDispatch;
751
+ }),
736
752
  }),
737
753
  );
738
754
  dispatch = "dispatched";
@@ -815,7 +831,6 @@ export const makeProtectedBrowserPolicy = Effect.fn("ProtectedBrowser.open")(fun
815
831
  Effect.gen(function* () {
816
832
  if (detached || observation === "closed") return yield* fail("closed");
817
833
  if (!suspended) return yield* fail("denied");
818
- yield* permitObservation;
819
834
  offers.clear();
820
835
  driver.resetReferences();
821
836
  needsObservation = true;