@sudobility/sider_types 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +29 -0
- package/dist/actions.js +4 -0
- package/dist/api.d.ts +54 -0
- package/dist/api.js +4 -0
- package/dist/common.d.ts +28 -0
- package/dist/common.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +12 -0
- package/dist/local.d.ts +20 -0
- package/dist/local.js +8 -0
- package/dist/registry.d.ts +215 -0
- package/dist/registry.js +10 -0
- package/dist/runtime.d.ts +96 -0
- package/dist/runtime.js +8 -0
- package/package.json +23 -0
- package/src/actions.ts +43 -0
- package/src/api.ts +68 -0
- package/src/common.ts +41 -0
- package/src/index.ts +13 -0
- package/src/local.ts +29 -0
- package/src/registry.ts +258 -0
- package/src/runtime.ts +144 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type OutcomeCategory = "gate" | "http" | "not_found" | "no_effect" | "precondition";
|
|
2
|
+
export interface ActionOutcome {
|
|
3
|
+
/** ok = did what was asked; blocked = known reportable refusal; failed = unexpected. */
|
|
4
|
+
status: "ok" | "blocked" | "failed";
|
|
5
|
+
/** Closed mechanism vocabulary (branch/color on this). */
|
|
6
|
+
category?: OutcomeCategory;
|
|
7
|
+
/** OPEN, domain-agnostic reason slug: "gate_same_origin", "pre_order",
|
|
8
|
+
* "already_following", "login_required", … Not an enum. */
|
|
9
|
+
reason?: string;
|
|
10
|
+
/** Human-readable detail / evidence. */
|
|
11
|
+
detail?: string;
|
|
12
|
+
/** Tokenized + size-capped payload on ok (read items / response body). */
|
|
13
|
+
data?: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** One item extracted from a rendered result collection by readPage. */
|
|
16
|
+
export interface ExtractedItem {
|
|
17
|
+
title: string;
|
|
18
|
+
price?: string;
|
|
19
|
+
url?: string;
|
|
20
|
+
/** Availability phrase found near the item ("pre-order", "out of stock"); absent = available. */
|
|
21
|
+
availability?: string;
|
|
22
|
+
imageUrl?: string;
|
|
23
|
+
/** href when present, else a resolved unique selector — used to open/click the item. */
|
|
24
|
+
ref: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ReadPageResult {
|
|
27
|
+
items: ExtractedItem[];
|
|
28
|
+
count: number;
|
|
29
|
+
}
|
package/dist/actions.js
ADDED
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { EndpointGraphEdge, SafetyClass, SecretSlot, Site, ToolSpec, UXRecipe } from "./registry";
|
|
2
|
+
import type { Observation, StepKind } from "./runtime";
|
|
3
|
+
/** A planner decision (mirror of the ShapeShyft plan-next-step output). */
|
|
4
|
+
export interface PlannerStep {
|
|
5
|
+
kind: StepKind;
|
|
6
|
+
toolId?: string;
|
|
7
|
+
args?: Record<string, unknown>;
|
|
8
|
+
safetyClass?: SafetyClass;
|
|
9
|
+
rationale?: string;
|
|
10
|
+
domAction?: {
|
|
11
|
+
type: "hover" | "click" | "type";
|
|
12
|
+
selector: string;
|
|
13
|
+
text?: string;
|
|
14
|
+
};
|
|
15
|
+
askPrompt?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SiteLookupResult {
|
|
18
|
+
known: boolean;
|
|
19
|
+
site?: Site;
|
|
20
|
+
hasTrustedTools?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** The MCP tool catalog served for a site (placeholder-only, safe to share). */
|
|
23
|
+
export interface ToolCatalog {
|
|
24
|
+
tools: ToolSpec[];
|
|
25
|
+
secretSlots: SecretSlot[];
|
|
26
|
+
edges: EndpointGraphEdge[];
|
|
27
|
+
uxRecipes: UXRecipe[];
|
|
28
|
+
}
|
|
29
|
+
export type ObservationUpload = Omit<Observation, "id" | "batchId" | "createdAt">;
|
|
30
|
+
export type SecretSlotUpload = Omit<SecretSlot, "siteId" | "createdAt" | "updatedAt">;
|
|
31
|
+
export interface CaptureRequest {
|
|
32
|
+
siteOrigin: string;
|
|
33
|
+
siteName?: string;
|
|
34
|
+
observations: ObservationUpload[];
|
|
35
|
+
secretSlots?: SecretSlotUpload[];
|
|
36
|
+
}
|
|
37
|
+
export interface CaptureResponse {
|
|
38
|
+
batchId: string;
|
|
39
|
+
siteId: string;
|
|
40
|
+
}
|
|
41
|
+
export interface PlanStartResponse {
|
|
42
|
+
runId: string;
|
|
43
|
+
step: PlannerStep;
|
|
44
|
+
}
|
|
45
|
+
export interface PlanStepResponse {
|
|
46
|
+
step: PlannerStep;
|
|
47
|
+
}
|
|
48
|
+
/** Public aggregate stats for the marketing site. */
|
|
49
|
+
export interface StatsResponse {
|
|
50
|
+
siteCount: number;
|
|
51
|
+
toolCount: number;
|
|
52
|
+
trustedToolCount: number;
|
|
53
|
+
contributorCount: number;
|
|
54
|
+
}
|
package/dist/api.js
ADDED
package/dist/common.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** ISO-8601 timestamp string. */
|
|
2
|
+
export type IsoTimestamp = string;
|
|
3
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
4
|
+
/**
|
|
5
|
+
* Minimal JSON Schema representation. Sider stores inferred request/response
|
|
6
|
+
* shapes and tool input schemas as JSON Schema so they are portable to MCP.
|
|
7
|
+
*/
|
|
8
|
+
export interface JSONSchema {
|
|
9
|
+
type?: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null";
|
|
10
|
+
properties?: Record<string, JSONSchema>;
|
|
11
|
+
items?: JSONSchema;
|
|
12
|
+
required?: string[];
|
|
13
|
+
enum?: unknown[];
|
|
14
|
+
const?: unknown;
|
|
15
|
+
description?: string;
|
|
16
|
+
format?: string;
|
|
17
|
+
[k: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
/** Standard success/error envelope returned by sider_api. */
|
|
20
|
+
export type ApiResponse<T> = {
|
|
21
|
+
success: true;
|
|
22
|
+
data: T;
|
|
23
|
+
timestamp: IsoTimestamp;
|
|
24
|
+
} | {
|
|
25
|
+
success: false;
|
|
26
|
+
error: string;
|
|
27
|
+
timestamp: IsoTimestamp;
|
|
28
|
+
};
|
package/dist/common.js
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @sudobility/sider_types — shared domain types for Sider.
|
|
2
|
+
//
|
|
3
|
+
// Three tiers, one hard rule: a plaintext secret exists in exactly ONE of them.
|
|
4
|
+
// - GLOBAL (registry.ts): shared across all users; placeholders only.
|
|
5
|
+
// - PRIVATE (runtime.ts): per-user server data; uploaded already tokenized.
|
|
6
|
+
// - LOCAL (local.ts): browser only; the sole holder of real secret values.
|
|
7
|
+
export * from "./common";
|
|
8
|
+
export * from "./registry";
|
|
9
|
+
export * from "./runtime";
|
|
10
|
+
export * from "./local";
|
|
11
|
+
export * from "./api";
|
|
12
|
+
export * from "./actions";
|
package/dist/local.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IsoTimestamp } from "./common";
|
|
2
|
+
import type { ResolverHint } from "./registry";
|
|
3
|
+
/**
|
|
4
|
+
* Maps a global SecretSlot to how its value is found in THIS user's session,
|
|
5
|
+
* and (transiently) to the value itself.
|
|
6
|
+
*
|
|
7
|
+
* `currentValue` is the ONLY field in the entire Sider type system that may
|
|
8
|
+
* hold a plaintext secret. It exists only in the tab that already legitimately
|
|
9
|
+
* holds the user's own credential, is read fresh at egress, and is never
|
|
10
|
+
* persisted to disk or transmitted anywhere.
|
|
11
|
+
*/
|
|
12
|
+
export interface TokenMapEntry {
|
|
13
|
+
/** Matches a global SecretSlot.id. */
|
|
14
|
+
slotId: string;
|
|
15
|
+
/** The hint that actually resolved a value in this session. */
|
|
16
|
+
resolver: ResolverHint;
|
|
17
|
+
/** Read fresh at egress; never persisted or transmitted. */
|
|
18
|
+
currentValue?: string;
|
|
19
|
+
lastSeenAt: IsoTimestamp;
|
|
20
|
+
}
|
package/dist/local.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// LOCAL TIER — browser only.
|
|
3
|
+
//
|
|
4
|
+
// Nothing in this file is EVER uploaded to sider_api, written to a server
|
|
5
|
+
// database, or placed in an LLM prompt. It lives in chrome.storage.session
|
|
6
|
+
// (per-tab, cleared on close) and in memory.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { HttpMethod, IsoTimestamp, JSONSchema } from "./common";
|
|
2
|
+
export interface SitePolicy {
|
|
3
|
+
/** If true, Sider is disabled on this origin (denylist: banking/health/etc.). */
|
|
4
|
+
blocked: boolean;
|
|
5
|
+
/** Whether the assistant may perform write/financial actions on this site. */
|
|
6
|
+
allowMutations: boolean;
|
|
7
|
+
/** Rate cap applied to Sider-issued requests on this origin. */
|
|
8
|
+
maxRequestsPerMinute: number;
|
|
9
|
+
}
|
|
10
|
+
export interface Site {
|
|
11
|
+
id: string;
|
|
12
|
+
/** Scheme + host (+ port). The trust/same-origin boundary. */
|
|
13
|
+
origin: string;
|
|
14
|
+
name: string;
|
|
15
|
+
policy: SitePolicy;
|
|
16
|
+
toolCount: number;
|
|
17
|
+
trustedToolCount: number;
|
|
18
|
+
contributorCount: number;
|
|
19
|
+
createdAt: IsoTimestamp;
|
|
20
|
+
updatedAt: IsoTimestamp;
|
|
21
|
+
}
|
|
22
|
+
export type EndpointCategory = "read" | "write" | "auth" | "telemetry" | "unknown";
|
|
23
|
+
export interface FieldSemantics {
|
|
24
|
+
/** JSON path within the request or response (e.g. "data.sections[].price"). */
|
|
25
|
+
jsonPath: string;
|
|
26
|
+
meaning: string;
|
|
27
|
+
type: string;
|
|
28
|
+
/** True if this field is an identifier (candidate for a data-flow edge). */
|
|
29
|
+
isId: boolean;
|
|
30
|
+
/** If this field feeds a param of another endpoint, the target template id. */
|
|
31
|
+
linksToTemplateId?: string;
|
|
32
|
+
isPII: boolean;
|
|
33
|
+
/** If true, this field is represented by a SecretSlot rather than a raw value. */
|
|
34
|
+
isSecret: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Which credentials an endpoint requires — described structurally, never by value. */
|
|
37
|
+
export interface AuthProfile {
|
|
38
|
+
/** SecretSlot ids that must be resolved at call time. */
|
|
39
|
+
requiredSlotIds: string[];
|
|
40
|
+
/** Header names observed carrying auth (values are never recorded). */
|
|
41
|
+
authHeaderNames: string[];
|
|
42
|
+
/** Whether the endpoint relies on cookies the browser attaches automatically. */
|
|
43
|
+
usesCookies: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface EndpointTemplate {
|
|
46
|
+
id: string;
|
|
47
|
+
siteId: string;
|
|
48
|
+
method: HttpMethod;
|
|
49
|
+
/** Path with params extracted: "/api/sections/{sectionId}/seats". */
|
|
50
|
+
pathTemplate: string;
|
|
51
|
+
/** For GraphQL: the operation name (the URL alone is not distinguishing). */
|
|
52
|
+
graphqlOperation?: string;
|
|
53
|
+
description: string;
|
|
54
|
+
category: EndpointCategory;
|
|
55
|
+
requestSchema: JSONSchema;
|
|
56
|
+
responseSchema: JSONSchema;
|
|
57
|
+
requestFields: FieldSemantics[];
|
|
58
|
+
responseFields: FieldSemantics[];
|
|
59
|
+
authProfile: AuthProfile;
|
|
60
|
+
observationCount: number;
|
|
61
|
+
corroboratingUserCount: number;
|
|
62
|
+
confidence: number;
|
|
63
|
+
createdAt: IsoTimestamp;
|
|
64
|
+
updatedAt: IsoTimestamp;
|
|
65
|
+
}
|
|
66
|
+
export type SecretKind = "bearer" | "csrf" | "api_key" | "session" | "signature" | "pii" | "unknown";
|
|
67
|
+
export type SecretRole = "auto_cookie" | "active_inject";
|
|
68
|
+
/** WHERE a secret is allowed to be placed — enforced at egress (Gate B). */
|
|
69
|
+
export type InjectionLocation = {
|
|
70
|
+
at: "header";
|
|
71
|
+
name: string;
|
|
72
|
+
} | {
|
|
73
|
+
at: "query";
|
|
74
|
+
param: string;
|
|
75
|
+
} | {
|
|
76
|
+
at: "body";
|
|
77
|
+
jsonPath: string;
|
|
78
|
+
} | {
|
|
79
|
+
at: "cookie";
|
|
80
|
+
name: string;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* WHERE to find the current value of a secret in the user's own session.
|
|
84
|
+
* Carries structural identifiers (cookie NAME, storage KEY, selector) only —
|
|
85
|
+
* never the value itself. Each user's browser resolves its own value.
|
|
86
|
+
*/
|
|
87
|
+
export type ResolverHint = {
|
|
88
|
+
from: "cookie";
|
|
89
|
+
name: string;
|
|
90
|
+
} | {
|
|
91
|
+
from: "storage";
|
|
92
|
+
area: "local" | "session";
|
|
93
|
+
key: string;
|
|
94
|
+
} | {
|
|
95
|
+
from: "dom";
|
|
96
|
+
selector: string;
|
|
97
|
+
attr?: string;
|
|
98
|
+
} | {
|
|
99
|
+
from: "response";
|
|
100
|
+
endpointTemplateId: string;
|
|
101
|
+
jsonPath: string;
|
|
102
|
+
};
|
|
103
|
+
export interface SecretSlot {
|
|
104
|
+
/** Placeholder id used in recipes and tokenized samples, e.g. "site:<id>:auth_bearer". */
|
|
105
|
+
id: string;
|
|
106
|
+
siteId: string;
|
|
107
|
+
kind: SecretKind;
|
|
108
|
+
role: SecretRole;
|
|
109
|
+
injectionLocation: InjectionLocation;
|
|
110
|
+
/** Same-origin lock (Gate A): a recipe host must equal this origin to use the slot. */
|
|
111
|
+
allowedDestination: string;
|
|
112
|
+
/** Ranked structural hints for locating the current value locally. Never values. */
|
|
113
|
+
resolverHints: ResolverHint[];
|
|
114
|
+
confidence: number;
|
|
115
|
+
createdAt: IsoTimestamp;
|
|
116
|
+
updatedAt: IsoTimestamp;
|
|
117
|
+
}
|
|
118
|
+
export type SafetyClass = "read" | "write" | "financial";
|
|
119
|
+
export type ToolStatus = "provisional" | "trusted" | "flagged";
|
|
120
|
+
/** Resolves a single `{key}` placeholder used anywhere in a recipe. */
|
|
121
|
+
export type ParamBinding = {
|
|
122
|
+
kind: "literal";
|
|
123
|
+
value: string;
|
|
124
|
+
} | {
|
|
125
|
+
kind: "arg";
|
|
126
|
+
argName: string;
|
|
127
|
+
} | {
|
|
128
|
+
kind: "secret";
|
|
129
|
+
slotId: string;
|
|
130
|
+
} | {
|
|
131
|
+
kind: "priorOutput";
|
|
132
|
+
stepRef: string;
|
|
133
|
+
jsonPath: string;
|
|
134
|
+
};
|
|
135
|
+
export interface HeaderTemplate {
|
|
136
|
+
name: string;
|
|
137
|
+
/** May contain `{key}` placeholders resolved via InvocationRecipe.bindings. */
|
|
138
|
+
valueTemplate: string;
|
|
139
|
+
}
|
|
140
|
+
export interface SignatureModel {
|
|
141
|
+
type: "none" | "hmac" | "unknown";
|
|
142
|
+
/** When type !== "none", the endpoint typically cannot be replayed via a
|
|
143
|
+
* direct call and must be driven through DOM emulation instead. */
|
|
144
|
+
note?: string;
|
|
145
|
+
}
|
|
146
|
+
/** One sub-call of a composite/paginating tool. */
|
|
147
|
+
export interface ComposeStep {
|
|
148
|
+
/** Referenced by later `{ kind: "priorOutput", stepRef }` bindings. */
|
|
149
|
+
ref: string;
|
|
150
|
+
toolId: string;
|
|
151
|
+
argBindings: Record<string, ParamBinding>;
|
|
152
|
+
/** If set, run once per element of the array at this jsonPath in the prior
|
|
153
|
+
* result (fan-out) — e.g. "for each section, fetch its seats". */
|
|
154
|
+
forEachJsonPath?: string;
|
|
155
|
+
}
|
|
156
|
+
export interface InvocationRecipe {
|
|
157
|
+
method: HttpMethod;
|
|
158
|
+
/** Path/template relative to the site origin. Placeholders: `{key}`. */
|
|
159
|
+
urlTemplate: string;
|
|
160
|
+
headers: HeaderTemplate[];
|
|
161
|
+
/** JSON body template; string values may contain `{key}` placeholders. */
|
|
162
|
+
bodyTemplate?: unknown;
|
|
163
|
+
credentials: "include";
|
|
164
|
+
/** Resolves every `{key}` used in urlTemplate / headers / bodyTemplate. */
|
|
165
|
+
bindings: Record<string, ParamBinding>;
|
|
166
|
+
signatureModel?: SignatureModel;
|
|
167
|
+
/** For composite/paginating tools: ordered sub-calls that feed later bindings. */
|
|
168
|
+
compose?: ComposeStep[];
|
|
169
|
+
}
|
|
170
|
+
export interface ToolSpec {
|
|
171
|
+
id: string;
|
|
172
|
+
siteId: string;
|
|
173
|
+
name: string;
|
|
174
|
+
description: string;
|
|
175
|
+
/** Short imperative user-facing label ("Search for a product"); "" = none. */
|
|
176
|
+
capabilityLabel?: string;
|
|
177
|
+
inputSchema: JSONSchema;
|
|
178
|
+
safetyClass: SafetyClass;
|
|
179
|
+
/** false ⇒ signed/HMAC or otherwise non-replayable → DOM emulation only. */
|
|
180
|
+
directCallAvailable: boolean;
|
|
181
|
+
recipe: InvocationRecipe;
|
|
182
|
+
status: ToolStatus;
|
|
183
|
+
version: number;
|
|
184
|
+
observationCount: number;
|
|
185
|
+
/** Distinct users whose learned recipe corroborated this tool (trust gate). */
|
|
186
|
+
corroboratingUserCount: number;
|
|
187
|
+
confidence: number;
|
|
188
|
+
createdAt: IsoTimestamp;
|
|
189
|
+
updatedAt: IsoTimestamp;
|
|
190
|
+
}
|
|
191
|
+
export interface EndpointGraphEdge {
|
|
192
|
+
id: string;
|
|
193
|
+
siteId: string;
|
|
194
|
+
fromTemplateId: string;
|
|
195
|
+
/** Field in the source response that supplies the value. */
|
|
196
|
+
fromJsonPath: string;
|
|
197
|
+
toTemplateId: string;
|
|
198
|
+
/** Param of the target endpoint that the value feeds. */
|
|
199
|
+
toParam: string;
|
|
200
|
+
confidence: number;
|
|
201
|
+
}
|
|
202
|
+
export interface UXRecipe {
|
|
203
|
+
id: string;
|
|
204
|
+
siteId: string;
|
|
205
|
+
/** Natural-language goal pattern this recipe serves, e.g. "find cheapest seats". */
|
|
206
|
+
goalPattern: string;
|
|
207
|
+
/** Key of a generative-UI component the extension knows how to render. */
|
|
208
|
+
componentKey: string;
|
|
209
|
+
/** How to source the component's data. */
|
|
210
|
+
binding: {
|
|
211
|
+
toolId: string;
|
|
212
|
+
argBindings: Record<string, ParamBinding>;
|
|
213
|
+
};
|
|
214
|
+
status: ToolStatus;
|
|
215
|
+
}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// GLOBAL TIER — the shared registry.
|
|
3
|
+
//
|
|
4
|
+
// Every type in this file is shared across ALL users of a site. It therefore
|
|
5
|
+
// may NEVER contain a plaintext secret. Secrets appear only as placeholder
|
|
6
|
+
// references to SecretSlot ids (e.g. "{key}" bound to { kind: "secret", slotId }).
|
|
7
|
+
// The plaintext value of a secret lives exclusively in the browser (see
|
|
8
|
+
// ./local.ts — TokenMapEntry).
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { HttpMethod, IsoTimestamp } from "./common";
|
|
2
|
+
import type { SafetyClass } from "./registry";
|
|
3
|
+
export interface RequestContext {
|
|
4
|
+
/** Page route when the request fired. */
|
|
5
|
+
route: string;
|
|
6
|
+
/** DOM element the user interacted with just before the request, if any. */
|
|
7
|
+
triggerSelector?: string;
|
|
8
|
+
pageTitle?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A single observed request/response.
|
|
12
|
+
*
|
|
13
|
+
* TOKENIZED: every secret value is already a "{{slot:…}}" placeholder before
|
|
14
|
+
* this object leaves the browser. Auth header values are placeholders or were
|
|
15
|
+
* dropped entirely in the browser's redaction pre-pass.
|
|
16
|
+
*/
|
|
17
|
+
export interface Observation {
|
|
18
|
+
id: string;
|
|
19
|
+
batchId: string;
|
|
20
|
+
/** Assigned during clustering. */
|
|
21
|
+
endpointTemplateId?: string;
|
|
22
|
+
method: HttpMethod;
|
|
23
|
+
url: string;
|
|
24
|
+
requestHeaders: Record<string, string>;
|
|
25
|
+
requestBody?: unknown;
|
|
26
|
+
status: number;
|
|
27
|
+
responseBody?: unknown;
|
|
28
|
+
timingMs: number;
|
|
29
|
+
context: RequestContext;
|
|
30
|
+
createdAt: IsoTimestamp;
|
|
31
|
+
}
|
|
32
|
+
export type CaptureBatchStatus = "buffering" | "uploaded" | "distilled" | "discarded";
|
|
33
|
+
export interface CaptureBatch {
|
|
34
|
+
id: string;
|
|
35
|
+
contributorId: string;
|
|
36
|
+
siteId: string;
|
|
37
|
+
status: CaptureBatchStatus;
|
|
38
|
+
observationCount: number;
|
|
39
|
+
createdAt: IsoTimestamp;
|
|
40
|
+
}
|
|
41
|
+
export type StepKind = "tool_call" | "dom_action" | "ask_user" | "done";
|
|
42
|
+
export type StepStatus = "pending" | "awaiting_confirm" | "running" | "done" | "error" | "aborted";
|
|
43
|
+
export interface PlanStep {
|
|
44
|
+
id: string;
|
|
45
|
+
runId: string;
|
|
46
|
+
index: number;
|
|
47
|
+
kind: StepKind;
|
|
48
|
+
toolId?: string;
|
|
49
|
+
safetyClass?: SafetyClass;
|
|
50
|
+
/** Shape/keys of args only — never secret values. */
|
|
51
|
+
argsShape?: unknown;
|
|
52
|
+
status: StepStatus;
|
|
53
|
+
/** Shape of the result — never secret values. */
|
|
54
|
+
resultShape?: unknown;
|
|
55
|
+
rationale?: string;
|
|
56
|
+
error?: string;
|
|
57
|
+
startedAt?: IsoTimestamp;
|
|
58
|
+
finishedAt?: IsoTimestamp;
|
|
59
|
+
}
|
|
60
|
+
export type PlanRunStatus = "planning" | "awaiting_approval" | "running" | "completed" | "aborted" | "error";
|
|
61
|
+
export interface PlanRun {
|
|
62
|
+
id: string;
|
|
63
|
+
contributorId: string;
|
|
64
|
+
siteId: string;
|
|
65
|
+
goal: string;
|
|
66
|
+
status: PlanRunStatus;
|
|
67
|
+
createdAt: IsoTimestamp;
|
|
68
|
+
finishedAt?: IsoTimestamp;
|
|
69
|
+
}
|
|
70
|
+
export interface Contributor {
|
|
71
|
+
firebaseUid: string;
|
|
72
|
+
reputation: number;
|
|
73
|
+
createdAt: IsoTimestamp;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Output of sider_lib compiling a ToolSpec + args, BEFORE detokenization.
|
|
77
|
+
* Placeholders are still present; secrets are substituted only after all three
|
|
78
|
+
* egress gates pass.
|
|
79
|
+
*/
|
|
80
|
+
export interface CompiledRequest {
|
|
81
|
+
method: HttpMethod;
|
|
82
|
+
url: string;
|
|
83
|
+
headers: Record<string, string>;
|
|
84
|
+
body?: unknown;
|
|
85
|
+
credentials: "include";
|
|
86
|
+
referencedSlotIds: string[];
|
|
87
|
+
safetyClass: SafetyClass;
|
|
88
|
+
}
|
|
89
|
+
/** Result of an egress gate check (same-origin / injection-location / safety). */
|
|
90
|
+
export type GateOutcome = {
|
|
91
|
+
ok: true;
|
|
92
|
+
} | {
|
|
93
|
+
ok: false;
|
|
94
|
+
gate: "same_origin" | "injection_location" | "safety";
|
|
95
|
+
reason: string;
|
|
96
|
+
};
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// PRIVATE TIER (per-user server data) + browser-side execution helper types.
|
|
3
|
+
//
|
|
4
|
+
// Capture data reaches this tier already TOKENIZED — every secret value is a
|
|
5
|
+
// placeholder before it ever leaves the browser. Plan/audit records store the
|
|
6
|
+
// SHAPE of args and results, never secret values.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sudobility/sider_types",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Shared domain types for Sider — AI assistance for generic web apps.",
|
|
5
|
+
"license": "BUSL-1.1",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "src/index.ts",
|
|
11
|
+
"types": "src/index.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json",
|
|
18
|
+
"typecheck": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.9.3"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/actions.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Structured results for the three model-facing browser actions (callSiderTool,
|
|
2
|
+
// readPage, siderDomAction). One shape so the agent can aggregate outcomes and
|
|
3
|
+
// report a status summary (e.g. "added 3/5; 2 pre-order only").
|
|
4
|
+
|
|
5
|
+
// Closed, mechanism-level category — what Sider's own execution can determine.
|
|
6
|
+
// Domain-specific "why" lives in the open `reason`/`detail`, never here.
|
|
7
|
+
export type OutcomeCategory =
|
|
8
|
+
| "gate" // a security gate refused the request
|
|
9
|
+
| "http" // the request returned a non-2xx status
|
|
10
|
+
| "not_found" // the tool or DOM target was missing
|
|
11
|
+
| "no_effect" // the action produced no observable result
|
|
12
|
+
| "precondition"; // a site-level condition blocked it (open-ended; see reason/detail)
|
|
13
|
+
|
|
14
|
+
export interface ActionOutcome {
|
|
15
|
+
/** ok = did what was asked; blocked = known reportable refusal; failed = unexpected. */
|
|
16
|
+
status: "ok" | "blocked" | "failed";
|
|
17
|
+
/** Closed mechanism vocabulary (branch/color on this). */
|
|
18
|
+
category?: OutcomeCategory;
|
|
19
|
+
/** OPEN, domain-agnostic reason slug: "gate_same_origin", "pre_order",
|
|
20
|
+
* "already_following", "login_required", … Not an enum. */
|
|
21
|
+
reason?: string;
|
|
22
|
+
/** Human-readable detail / evidence. */
|
|
23
|
+
detail?: string;
|
|
24
|
+
/** Tokenized + size-capped payload on ok (read items / response body). */
|
|
25
|
+
data?: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** One item extracted from a rendered result collection by readPage. */
|
|
29
|
+
export interface ExtractedItem {
|
|
30
|
+
title: string;
|
|
31
|
+
price?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
/** Availability phrase found near the item ("pre-order", "out of stock"); absent = available. */
|
|
34
|
+
availability?: string;
|
|
35
|
+
imageUrl?: string;
|
|
36
|
+
/** href when present, else a resolved unique selector — used to open/click the item. */
|
|
37
|
+
ref: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ReadPageResult {
|
|
41
|
+
items: ExtractedItem[];
|
|
42
|
+
count: number;
|
|
43
|
+
}
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Wire contract for sider_api — the request/response DTOs shared by the server
|
|
2
|
+
// (to type its handlers) and sider_client (to type its calls). Keeping these
|
|
3
|
+
// here is the single source of truth that stops the two sides from drifting.
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
EndpointGraphEdge,
|
|
7
|
+
SafetyClass,
|
|
8
|
+
SecretSlot,
|
|
9
|
+
Site,
|
|
10
|
+
ToolSpec,
|
|
11
|
+
UXRecipe,
|
|
12
|
+
} from "./registry";
|
|
13
|
+
import type { Observation, StepKind } from "./runtime";
|
|
14
|
+
|
|
15
|
+
/** A planner decision (mirror of the ShapeShyft plan-next-step output). */
|
|
16
|
+
export interface PlannerStep {
|
|
17
|
+
kind: StepKind;
|
|
18
|
+
toolId?: string;
|
|
19
|
+
args?: Record<string, unknown>;
|
|
20
|
+
safetyClass?: SafetyClass;
|
|
21
|
+
rationale?: string;
|
|
22
|
+
domAction?: { type: "hover" | "click" | "type"; selector: string; text?: string };
|
|
23
|
+
askPrompt?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SiteLookupResult {
|
|
27
|
+
known: boolean;
|
|
28
|
+
site?: Site;
|
|
29
|
+
hasTrustedTools?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The MCP tool catalog served for a site (placeholder-only, safe to share). */
|
|
33
|
+
export interface ToolCatalog {
|
|
34
|
+
tools: ToolSpec[];
|
|
35
|
+
secretSlots: SecretSlot[];
|
|
36
|
+
edges: EndpointGraphEdge[];
|
|
37
|
+
uxRecipes: UXRecipe[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ObservationUpload = Omit<Observation, "id" | "batchId" | "createdAt">;
|
|
41
|
+
export type SecretSlotUpload = Omit<SecretSlot, "siteId" | "createdAt" | "updatedAt">;
|
|
42
|
+
|
|
43
|
+
export interface CaptureRequest {
|
|
44
|
+
siteOrigin: string;
|
|
45
|
+
siteName?: string;
|
|
46
|
+
observations: ObservationUpload[];
|
|
47
|
+
secretSlots?: SecretSlotUpload[];
|
|
48
|
+
}
|
|
49
|
+
export interface CaptureResponse {
|
|
50
|
+
batchId: string;
|
|
51
|
+
siteId: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface PlanStartResponse {
|
|
55
|
+
runId: string;
|
|
56
|
+
step: PlannerStep;
|
|
57
|
+
}
|
|
58
|
+
export interface PlanStepResponse {
|
|
59
|
+
step: PlannerStep;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Public aggregate stats for the marketing site. */
|
|
63
|
+
export interface StatsResponse {
|
|
64
|
+
siteCount: number;
|
|
65
|
+
toolCount: number;
|
|
66
|
+
trustedToolCount: number;
|
|
67
|
+
contributorCount: number;
|
|
68
|
+
}
|
package/src/common.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Common primitives shared across all Sider tiers.
|
|
2
|
+
|
|
3
|
+
/** ISO-8601 timestamp string. */
|
|
4
|
+
export type IsoTimestamp = string;
|
|
5
|
+
|
|
6
|
+
export type HttpMethod =
|
|
7
|
+
| "GET"
|
|
8
|
+
| "POST"
|
|
9
|
+
| "PUT"
|
|
10
|
+
| "PATCH"
|
|
11
|
+
| "DELETE"
|
|
12
|
+
| "HEAD"
|
|
13
|
+
| "OPTIONS";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal JSON Schema representation. Sider stores inferred request/response
|
|
17
|
+
* shapes and tool input schemas as JSON Schema so they are portable to MCP.
|
|
18
|
+
*/
|
|
19
|
+
export interface JSONSchema {
|
|
20
|
+
type?:
|
|
21
|
+
| "object"
|
|
22
|
+
| "array"
|
|
23
|
+
| "string"
|
|
24
|
+
| "number"
|
|
25
|
+
| "integer"
|
|
26
|
+
| "boolean"
|
|
27
|
+
| "null";
|
|
28
|
+
properties?: Record<string, JSONSchema>;
|
|
29
|
+
items?: JSONSchema;
|
|
30
|
+
required?: string[];
|
|
31
|
+
enum?: unknown[];
|
|
32
|
+
const?: unknown;
|
|
33
|
+
description?: string;
|
|
34
|
+
format?: string;
|
|
35
|
+
[k: string]: unknown;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Standard success/error envelope returned by sider_api. */
|
|
39
|
+
export type ApiResponse<T> =
|
|
40
|
+
| { success: true; data: T; timestamp: IsoTimestamp }
|
|
41
|
+
| { success: false; error: string; timestamp: IsoTimestamp };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @sudobility/sider_types — shared domain types for Sider.
|
|
2
|
+
//
|
|
3
|
+
// Three tiers, one hard rule: a plaintext secret exists in exactly ONE of them.
|
|
4
|
+
// - GLOBAL (registry.ts): shared across all users; placeholders only.
|
|
5
|
+
// - PRIVATE (runtime.ts): per-user server data; uploaded already tokenized.
|
|
6
|
+
// - LOCAL (local.ts): browser only; the sole holder of real secret values.
|
|
7
|
+
|
|
8
|
+
export * from "./common";
|
|
9
|
+
export * from "./registry";
|
|
10
|
+
export * from "./runtime";
|
|
11
|
+
export * from "./local";
|
|
12
|
+
export * from "./api";
|
|
13
|
+
export * from "./actions";
|
package/src/local.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// LOCAL TIER — browser only.
|
|
3
|
+
//
|
|
4
|
+
// Nothing in this file is EVER uploaded to sider_api, written to a server
|
|
5
|
+
// database, or placed in an LLM prompt. It lives in chrome.storage.session
|
|
6
|
+
// (per-tab, cleared on close) and in memory.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
import type { IsoTimestamp } from "./common";
|
|
10
|
+
import type { ResolverHint } from "./registry";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Maps a global SecretSlot to how its value is found in THIS user's session,
|
|
14
|
+
* and (transiently) to the value itself.
|
|
15
|
+
*
|
|
16
|
+
* `currentValue` is the ONLY field in the entire Sider type system that may
|
|
17
|
+
* hold a plaintext secret. It exists only in the tab that already legitimately
|
|
18
|
+
* holds the user's own credential, is read fresh at egress, and is never
|
|
19
|
+
* persisted to disk or transmitted anywhere.
|
|
20
|
+
*/
|
|
21
|
+
export interface TokenMapEntry {
|
|
22
|
+
/** Matches a global SecretSlot.id. */
|
|
23
|
+
slotId: string;
|
|
24
|
+
/** The hint that actually resolved a value in this session. */
|
|
25
|
+
resolver: ResolverHint;
|
|
26
|
+
/** Read fresh at egress; never persisted or transmitted. */
|
|
27
|
+
currentValue?: string;
|
|
28
|
+
lastSeenAt: IsoTimestamp;
|
|
29
|
+
}
|
package/src/registry.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// GLOBAL TIER — the shared registry.
|
|
3
|
+
//
|
|
4
|
+
// Every type in this file is shared across ALL users of a site. It therefore
|
|
5
|
+
// may NEVER contain a plaintext secret. Secrets appear only as placeholder
|
|
6
|
+
// references to SecretSlot ids (e.g. "{key}" bound to { kind: "secret", slotId }).
|
|
7
|
+
// The plaintext value of a secret lives exclusively in the browser (see
|
|
8
|
+
// ./local.ts — TokenMapEntry).
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
import type { HttpMethod, IsoTimestamp, JSONSchema } from "./common";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Site
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export interface SitePolicy {
|
|
18
|
+
/** If true, Sider is disabled on this origin (denylist: banking/health/etc.). */
|
|
19
|
+
blocked: boolean;
|
|
20
|
+
/** Whether the assistant may perform write/financial actions on this site. */
|
|
21
|
+
allowMutations: boolean;
|
|
22
|
+
/** Rate cap applied to Sider-issued requests on this origin. */
|
|
23
|
+
maxRequestsPerMinute: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Site {
|
|
27
|
+
id: string;
|
|
28
|
+
/** Scheme + host (+ port). The trust/same-origin boundary. */
|
|
29
|
+
origin: string;
|
|
30
|
+
name: string;
|
|
31
|
+
policy: SitePolicy;
|
|
32
|
+
toolCount: number;
|
|
33
|
+
trustedToolCount: number;
|
|
34
|
+
contributorCount: number;
|
|
35
|
+
createdAt: IsoTimestamp;
|
|
36
|
+
updatedAt: IsoTimestamp;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Endpoint templates
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
export type EndpointCategory =
|
|
44
|
+
| "read"
|
|
45
|
+
| "write"
|
|
46
|
+
| "auth"
|
|
47
|
+
| "telemetry"
|
|
48
|
+
| "unknown";
|
|
49
|
+
|
|
50
|
+
export interface FieldSemantics {
|
|
51
|
+
/** JSON path within the request or response (e.g. "data.sections[].price"). */
|
|
52
|
+
jsonPath: string;
|
|
53
|
+
meaning: string;
|
|
54
|
+
type: string;
|
|
55
|
+
/** True if this field is an identifier (candidate for a data-flow edge). */
|
|
56
|
+
isId: boolean;
|
|
57
|
+
/** If this field feeds a param of another endpoint, the target template id. */
|
|
58
|
+
linksToTemplateId?: string;
|
|
59
|
+
isPII: boolean;
|
|
60
|
+
/** If true, this field is represented by a SecretSlot rather than a raw value. */
|
|
61
|
+
isSecret: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Which credentials an endpoint requires — described structurally, never by value. */
|
|
65
|
+
export interface AuthProfile {
|
|
66
|
+
/** SecretSlot ids that must be resolved at call time. */
|
|
67
|
+
requiredSlotIds: string[];
|
|
68
|
+
/** Header names observed carrying auth (values are never recorded). */
|
|
69
|
+
authHeaderNames: string[];
|
|
70
|
+
/** Whether the endpoint relies on cookies the browser attaches automatically. */
|
|
71
|
+
usesCookies: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface EndpointTemplate {
|
|
75
|
+
id: string;
|
|
76
|
+
siteId: string;
|
|
77
|
+
method: HttpMethod;
|
|
78
|
+
/** Path with params extracted: "/api/sections/{sectionId}/seats". */
|
|
79
|
+
pathTemplate: string;
|
|
80
|
+
/** For GraphQL: the operation name (the URL alone is not distinguishing). */
|
|
81
|
+
graphqlOperation?: string;
|
|
82
|
+
description: string;
|
|
83
|
+
category: EndpointCategory;
|
|
84
|
+
requestSchema: JSONSchema;
|
|
85
|
+
responseSchema: JSONSchema;
|
|
86
|
+
requestFields: FieldSemantics[];
|
|
87
|
+
responseFields: FieldSemantics[];
|
|
88
|
+
authProfile: AuthProfile;
|
|
89
|
+
observationCount: number;
|
|
90
|
+
corroboratingUserCount: number;
|
|
91
|
+
confidence: number;
|
|
92
|
+
createdAt: IsoTimestamp;
|
|
93
|
+
updatedAt: IsoTimestamp;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Secret slots — the shareable DEFINITION of a secret (never its value).
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
export type SecretKind =
|
|
101
|
+
| "bearer"
|
|
102
|
+
| "csrf"
|
|
103
|
+
| "api_key"
|
|
104
|
+
| "session"
|
|
105
|
+
| "signature"
|
|
106
|
+
| "pii"
|
|
107
|
+
| "unknown";
|
|
108
|
+
|
|
109
|
+
export type SecretRole =
|
|
110
|
+
// Browser attaches it automatically (credentials:'include'); the slot exists
|
|
111
|
+
// ONLY so samples get placeholder-ized. No substitution at execution.
|
|
112
|
+
| "auto_cookie"
|
|
113
|
+
// Must be resolved locally and substituted at egress (JS-set headers, CSRF,
|
|
114
|
+
// body fields, query params).
|
|
115
|
+
| "active_inject";
|
|
116
|
+
|
|
117
|
+
/** WHERE a secret is allowed to be placed — enforced at egress (Gate B). */
|
|
118
|
+
export type InjectionLocation =
|
|
119
|
+
| { at: "header"; name: string }
|
|
120
|
+
| { at: "query"; param: string }
|
|
121
|
+
| { at: "body"; jsonPath: string }
|
|
122
|
+
| { at: "cookie"; name: string };
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* WHERE to find the current value of a secret in the user's own session.
|
|
126
|
+
* Carries structural identifiers (cookie NAME, storage KEY, selector) only —
|
|
127
|
+
* never the value itself. Each user's browser resolves its own value.
|
|
128
|
+
*/
|
|
129
|
+
export type ResolverHint =
|
|
130
|
+
| { from: "cookie"; name: string }
|
|
131
|
+
| { from: "storage"; area: "local" | "session"; key: string }
|
|
132
|
+
| { from: "dom"; selector: string; attr?: string }
|
|
133
|
+
| { from: "response"; endpointTemplateId: string; jsonPath: string };
|
|
134
|
+
|
|
135
|
+
export interface SecretSlot {
|
|
136
|
+
/** Placeholder id used in recipes and tokenized samples, e.g. "site:<id>:auth_bearer". */
|
|
137
|
+
id: string;
|
|
138
|
+
siteId: string;
|
|
139
|
+
kind: SecretKind;
|
|
140
|
+
role: SecretRole;
|
|
141
|
+
injectionLocation: InjectionLocation;
|
|
142
|
+
/** Same-origin lock (Gate A): a recipe host must equal this origin to use the slot. */
|
|
143
|
+
allowedDestination: string;
|
|
144
|
+
/** Ranked structural hints for locating the current value locally. Never values. */
|
|
145
|
+
resolverHints: ResolverHint[];
|
|
146
|
+
confidence: number;
|
|
147
|
+
createdAt: IsoTimestamp;
|
|
148
|
+
updatedAt: IsoTimestamp;
|
|
149
|
+
// INVARIANT: there is deliberately NO `value` field, and never will be. A
|
|
150
|
+
// secret's plaintext exists only in the browser tab that already holds the
|
|
151
|
+
// user's own session (see ./local.ts — TokenMapEntry.currentValue).
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Tools (MCP-shaped) + invocation recipes
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
export type SafetyClass = "read" | "write" | "financial";
|
|
159
|
+
export type ToolStatus = "provisional" | "trusted" | "flagged";
|
|
160
|
+
|
|
161
|
+
/** Resolves a single `{key}` placeholder used anywhere in a recipe. */
|
|
162
|
+
export type ParamBinding =
|
|
163
|
+
| { kind: "literal"; value: string }
|
|
164
|
+
| { kind: "arg"; argName: string } // from the tool inputSchema / the user
|
|
165
|
+
| { kind: "secret"; slotId: string } // resolved LOCALLY at egress
|
|
166
|
+
| { kind: "priorOutput"; stepRef: string; jsonPath: string }; // graph edge, this run
|
|
167
|
+
|
|
168
|
+
export interface HeaderTemplate {
|
|
169
|
+
name: string;
|
|
170
|
+
/** May contain `{key}` placeholders resolved via InvocationRecipe.bindings. */
|
|
171
|
+
valueTemplate: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface SignatureModel {
|
|
175
|
+
type: "none" | "hmac" | "unknown";
|
|
176
|
+
/** When type !== "none", the endpoint typically cannot be replayed via a
|
|
177
|
+
* direct call and must be driven through DOM emulation instead. */
|
|
178
|
+
note?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** One sub-call of a composite/paginating tool. */
|
|
182
|
+
export interface ComposeStep {
|
|
183
|
+
/** Referenced by later `{ kind: "priorOutput", stepRef }` bindings. */
|
|
184
|
+
ref: string;
|
|
185
|
+
toolId: string;
|
|
186
|
+
argBindings: Record<string, ParamBinding>;
|
|
187
|
+
/** If set, run once per element of the array at this jsonPath in the prior
|
|
188
|
+
* result (fan-out) — e.g. "for each section, fetch its seats". */
|
|
189
|
+
forEachJsonPath?: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface InvocationRecipe {
|
|
193
|
+
method: HttpMethod;
|
|
194
|
+
/** Path/template relative to the site origin. Placeholders: `{key}`. */
|
|
195
|
+
urlTemplate: string;
|
|
196
|
+
headers: HeaderTemplate[];
|
|
197
|
+
/** JSON body template; string values may contain `{key}` placeholders. */
|
|
198
|
+
bodyTemplate?: unknown;
|
|
199
|
+
credentials: "include";
|
|
200
|
+
/** Resolves every `{key}` used in urlTemplate / headers / bodyTemplate. */
|
|
201
|
+
bindings: Record<string, ParamBinding>;
|
|
202
|
+
signatureModel?: SignatureModel;
|
|
203
|
+
/** For composite/paginating tools: ordered sub-calls that feed later bindings. */
|
|
204
|
+
compose?: ComposeStep[];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface ToolSpec {
|
|
208
|
+
id: string;
|
|
209
|
+
siteId: string;
|
|
210
|
+
name: string;
|
|
211
|
+
description: string;
|
|
212
|
+
/** Short imperative user-facing label ("Search for a product"); "" = none. */
|
|
213
|
+
capabilityLabel?: string;
|
|
214
|
+
inputSchema: JSONSchema;
|
|
215
|
+
safetyClass: SafetyClass;
|
|
216
|
+
/** false ⇒ signed/HMAC or otherwise non-replayable → DOM emulation only. */
|
|
217
|
+
directCallAvailable: boolean;
|
|
218
|
+
recipe: InvocationRecipe;
|
|
219
|
+
status: ToolStatus;
|
|
220
|
+
version: number;
|
|
221
|
+
observationCount: number;
|
|
222
|
+
/** Distinct users whose learned recipe corroborated this tool (trust gate). */
|
|
223
|
+
corroboratingUserCount: number;
|
|
224
|
+
confidence: number;
|
|
225
|
+
createdAt: IsoTimestamp;
|
|
226
|
+
updatedAt: IsoTimestamp;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// Endpoint graph + UX recipes
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
export interface EndpointGraphEdge {
|
|
234
|
+
id: string;
|
|
235
|
+
siteId: string;
|
|
236
|
+
fromTemplateId: string;
|
|
237
|
+
/** Field in the source response that supplies the value. */
|
|
238
|
+
fromJsonPath: string;
|
|
239
|
+
toTemplateId: string;
|
|
240
|
+
/** Param of the target endpoint that the value feeds. */
|
|
241
|
+
toParam: string;
|
|
242
|
+
confidence: number;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface UXRecipe {
|
|
246
|
+
id: string;
|
|
247
|
+
siteId: string;
|
|
248
|
+
/** Natural-language goal pattern this recipe serves, e.g. "find cheapest seats". */
|
|
249
|
+
goalPattern: string;
|
|
250
|
+
/** Key of a generative-UI component the extension knows how to render. */
|
|
251
|
+
componentKey: string;
|
|
252
|
+
/** How to source the component's data. */
|
|
253
|
+
binding: {
|
|
254
|
+
toolId: string;
|
|
255
|
+
argBindings: Record<string, ParamBinding>;
|
|
256
|
+
};
|
|
257
|
+
status: ToolStatus;
|
|
258
|
+
}
|
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// PRIVATE TIER (per-user server data) + browser-side execution helper types.
|
|
3
|
+
//
|
|
4
|
+
// Capture data reaches this tier already TOKENIZED — every secret value is a
|
|
5
|
+
// placeholder before it ever leaves the browser. Plan/audit records store the
|
|
6
|
+
// SHAPE of args and results, never secret values.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
import type { HttpMethod, IsoTimestamp } from "./common";
|
|
10
|
+
import type { SafetyClass } from "./registry";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Capture (PRIVATE, tokenized before upload)
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
export interface RequestContext {
|
|
17
|
+
/** Page route when the request fired. */
|
|
18
|
+
route: string;
|
|
19
|
+
/** DOM element the user interacted with just before the request, if any. */
|
|
20
|
+
triggerSelector?: string;
|
|
21
|
+
pageTitle?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A single observed request/response.
|
|
26
|
+
*
|
|
27
|
+
* TOKENIZED: every secret value is already a "{{slot:…}}" placeholder before
|
|
28
|
+
* this object leaves the browser. Auth header values are placeholders or were
|
|
29
|
+
* dropped entirely in the browser's redaction pre-pass.
|
|
30
|
+
*/
|
|
31
|
+
export interface Observation {
|
|
32
|
+
id: string;
|
|
33
|
+
batchId: string;
|
|
34
|
+
/** Assigned during clustering. */
|
|
35
|
+
endpointTemplateId?: string;
|
|
36
|
+
method: HttpMethod;
|
|
37
|
+
url: string;
|
|
38
|
+
requestHeaders: Record<string, string>;
|
|
39
|
+
requestBody?: unknown;
|
|
40
|
+
status: number;
|
|
41
|
+
responseBody?: unknown;
|
|
42
|
+
timingMs: number;
|
|
43
|
+
context: RequestContext;
|
|
44
|
+
createdAt: IsoTimestamp;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type CaptureBatchStatus =
|
|
48
|
+
| "buffering"
|
|
49
|
+
| "uploaded"
|
|
50
|
+
| "distilled"
|
|
51
|
+
| "discarded";
|
|
52
|
+
|
|
53
|
+
export interface CaptureBatch {
|
|
54
|
+
id: string;
|
|
55
|
+
contributorId: string;
|
|
56
|
+
siteId: string;
|
|
57
|
+
status: CaptureBatchStatus;
|
|
58
|
+
observationCount: number;
|
|
59
|
+
createdAt: IsoTimestamp;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Planning / execution (PRIVATE audit)
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
export type StepKind = "tool_call" | "dom_action" | "ask_user" | "done";
|
|
67
|
+
|
|
68
|
+
export type StepStatus =
|
|
69
|
+
| "pending"
|
|
70
|
+
| "awaiting_confirm"
|
|
71
|
+
| "running"
|
|
72
|
+
| "done"
|
|
73
|
+
| "error"
|
|
74
|
+
| "aborted";
|
|
75
|
+
|
|
76
|
+
export interface PlanStep {
|
|
77
|
+
id: string;
|
|
78
|
+
runId: string;
|
|
79
|
+
index: number;
|
|
80
|
+
kind: StepKind;
|
|
81
|
+
toolId?: string;
|
|
82
|
+
safetyClass?: SafetyClass;
|
|
83
|
+
/** Shape/keys of args only — never secret values. */
|
|
84
|
+
argsShape?: unknown;
|
|
85
|
+
status: StepStatus;
|
|
86
|
+
/** Shape of the result — never secret values. */
|
|
87
|
+
resultShape?: unknown;
|
|
88
|
+
rationale?: string;
|
|
89
|
+
error?: string;
|
|
90
|
+
startedAt?: IsoTimestamp;
|
|
91
|
+
finishedAt?: IsoTimestamp;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type PlanRunStatus =
|
|
95
|
+
| "planning"
|
|
96
|
+
| "awaiting_approval"
|
|
97
|
+
| "running"
|
|
98
|
+
| "completed"
|
|
99
|
+
| "aborted"
|
|
100
|
+
| "error";
|
|
101
|
+
|
|
102
|
+
export interface PlanRun {
|
|
103
|
+
id: string;
|
|
104
|
+
contributorId: string;
|
|
105
|
+
siteId: string;
|
|
106
|
+
goal: string;
|
|
107
|
+
status: PlanRunStatus;
|
|
108
|
+
createdAt: IsoTimestamp;
|
|
109
|
+
finishedAt?: IsoTimestamp;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface Contributor {
|
|
113
|
+
firebaseUid: string;
|
|
114
|
+
reputation: number;
|
|
115
|
+
createdAt: IsoTimestamp;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Execution engine (browser-side) helper types
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Output of sider_lib compiling a ToolSpec + args, BEFORE detokenization.
|
|
124
|
+
* Placeholders are still present; secrets are substituted only after all three
|
|
125
|
+
* egress gates pass.
|
|
126
|
+
*/
|
|
127
|
+
export interface CompiledRequest {
|
|
128
|
+
method: HttpMethod;
|
|
129
|
+
url: string; // placeholders still present
|
|
130
|
+
headers: Record<string, string>;
|
|
131
|
+
body?: unknown;
|
|
132
|
+
credentials: "include";
|
|
133
|
+
referencedSlotIds: string[];
|
|
134
|
+
safetyClass: SafetyClass;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Result of an egress gate check (same-origin / injection-location / safety). */
|
|
138
|
+
export type GateOutcome =
|
|
139
|
+
| { ok: true }
|
|
140
|
+
| {
|
|
141
|
+
ok: false;
|
|
142
|
+
gate: "same_origin" | "injection_location" | "safety";
|
|
143
|
+
reason: string;
|
|
144
|
+
};
|