@extrovert.dev/sdk 0.1.0-pre.16 → 0.1.0-pre.17
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/README.md +17 -0
- package/dist/index.cjs +76 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -7
- package/dist/index.d.ts +40 -7
- package/dist/index.js +76 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -590,6 +590,23 @@ EXTROVERT_API_BASE_URL=mock npx tsx examples/wait-for-otp.ts
|
|
|
590
590
|
|
|
591
591
|
MIT © Message Science. *A side gate for agents.*
|
|
592
592
|
|
|
593
|
+
## Incoming-email activation
|
|
594
|
+
|
|
595
|
+
When signup returns `activation_method: "incoming_email"`, ask the human to send an
|
|
596
|
+
email from `human_email` to `address`. The inbox reservation expires at
|
|
597
|
+
`activation_expires_at`. Keep the temporary key and call `activationStatus()` until
|
|
598
|
+
`state` is `"proven"`, then call `verify({})` to receive the durable key. Pending keys
|
|
599
|
+
cannot read or send mail. `correctActivationEmail(humanEmail, revision)` clears any
|
|
600
|
+
previous proof and keeps the original deadline. Legacy signup responses that issued
|
|
601
|
+
an OTP still require that OTP until its original expiry.
|
|
602
|
+
|
|
603
|
+
Mail responses expose advisory `X-Extrovert-Storage-*` headers from 90% usage.
|
|
604
|
+
Use the exported `storageWarningFromHeaders(response.headers)` in a custom fetch
|
|
605
|
+
wrapper to read the threshold, byte counts, and cleanup/billing links without
|
|
606
|
+
consuming the response body. A missing or unavailable measurement is not zero usage.
|
|
607
|
+
Native writes enforce the cap; reads and deletion remain available. Deduplicate
|
|
608
|
+
human-facing suggestions within your session instead of repeating them on every read.
|
|
609
|
+
|
|
593
610
|
For choosing access and handing setup over to workers, read
|
|
594
611
|
[Connections and access](https://docs.extrovert.dev/concepts/connections-and-access/).
|
|
595
612
|
|
package/dist/index.cjs
CHANGED
|
@@ -1122,11 +1122,31 @@ ${parent.text}`;
|
|
|
1122
1122
|
}
|
|
1123
1123
|
var MockBackend = class {
|
|
1124
1124
|
constructor() {
|
|
1125
|
+
this.incomingActivation = false;
|
|
1125
1126
|
this.administrativeFixtures = new AdministrativeFixtures();
|
|
1126
1127
|
this.state = freshState();
|
|
1127
1128
|
/** Save / edit a rule (mock) - append-only by supersession (D11). */
|
|
1128
1129
|
this.learnedRules = /* @__PURE__ */ new Map();
|
|
1129
1130
|
}
|
|
1131
|
+
activationStatus() {
|
|
1132
|
+
const activation = this.pendingActivation;
|
|
1133
|
+
if (!activation) throw new Error("No incoming-email activation exists");
|
|
1134
|
+
if (activation.expires_ms <= Date.now() && activation.state !== "activated") activation.state = "expired";
|
|
1135
|
+
return { ...activation };
|
|
1136
|
+
}
|
|
1137
|
+
correctActivationEmail(email, revision) {
|
|
1138
|
+
const activation = this.activationStatus();
|
|
1139
|
+
if (activation.revision !== revision || !["pending", "proven"].includes(activation.state)) throw new Error("Activation changed or expired");
|
|
1140
|
+
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) throw new Error("Invalid human email");
|
|
1141
|
+
this.pendingActivation = { ...activation, human_email: email, revision: revision + 1, state: "pending" };
|
|
1142
|
+
return this.activationStatus();
|
|
1143
|
+
}
|
|
1144
|
+
/** Test-only trusted delivery; never available through a production client. */
|
|
1145
|
+
proveFixtureActivation(sender) {
|
|
1146
|
+
const activation = this.activationStatus();
|
|
1147
|
+
if (activation.state !== "pending" || sender !== activation.human_email) throw new Error("Activation sender mismatch or expired");
|
|
1148
|
+
this.pendingActivation = { ...activation, state: "proven" };
|
|
1149
|
+
}
|
|
1130
1150
|
configureAdministrativeFixture(credential) {
|
|
1131
1151
|
this.administrativeFixtures = new AdministrativeFixtures(credential);
|
|
1132
1152
|
}
|
|
@@ -1172,6 +1192,10 @@ var MockBackend = class {
|
|
|
1172
1192
|
const agentId = existing?.agentId ?? rid("agt");
|
|
1173
1193
|
const address = existing?.address ?? `${validatedSharedLocalPart(req.username ?? randomHandle())}@${FREE_SHARED_DOMAIN}`;
|
|
1174
1194
|
const otp = "492013";
|
|
1195
|
+
if (this.incomingActivation) {
|
|
1196
|
+
if (existing) throw new Error("Activation already pending; use the existing key");
|
|
1197
|
+
this.pendingActivation = { agent_id: agentId, address, human_email: email, created_ms: Date.now(), expires_ms: Date.now() + 864e5, revision: 1, state: "pending" };
|
|
1198
|
+
}
|
|
1175
1199
|
this.state.signupByEmail.set(email, { customerId, agentId, address, otp, verified: false });
|
|
1176
1200
|
return {
|
|
1177
1201
|
customer_id: customerId,
|
|
@@ -1181,16 +1205,24 @@ var MockBackend = class {
|
|
|
1181
1205
|
scopes: ["signup:verify"],
|
|
1182
1206
|
address,
|
|
1183
1207
|
verified: false,
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1208
|
+
...this.incomingActivation ? {
|
|
1209
|
+
activation_method: "incoming_email",
|
|
1210
|
+
human_email: email,
|
|
1211
|
+
activation_expires_at: new Date(this.pendingActivation.expires_ms).toISOString(),
|
|
1212
|
+
message: `Your agent\u2019s inbox is almost ready. Send an email from ${email} to ${address} to activate it and link it to your human email.`
|
|
1213
|
+
} : {
|
|
1214
|
+
otp_sent_to: email,
|
|
1215
|
+
otp_expires_at: new Date(Date.now() + 15 * 60 * 1e3).toISOString(),
|
|
1216
|
+
message: "A verification code was sent to your email. Call verify with it."
|
|
1217
|
+
}
|
|
1187
1218
|
};
|
|
1188
1219
|
}
|
|
1189
1220
|
/** Confirm a signup OTP and return a full-scope key (mock). */
|
|
1190
1221
|
verify(req) {
|
|
1191
1222
|
for (const [, s] of this.state.signupByEmail) {
|
|
1192
|
-
if (!s.verified && s.otp === req.otp.trim()) {
|
|
1223
|
+
if (!s.verified && (this.incomingActivation ? this.activationStatus().state === "proven" && this.pendingActivation?.agent_id === s.agentId : s.otp === (req.otp ?? "").trim())) {
|
|
1193
1224
|
s.verified = true;
|
|
1225
|
+
if (this.incomingActivation && this.pendingActivation) this.pendingActivation.state = "activated";
|
|
1194
1226
|
return {
|
|
1195
1227
|
agent_id: s.agentId,
|
|
1196
1228
|
agent_key: `pk_agent_${s.agentId.slice(4)}_${rid("sk").slice(3)}`,
|
|
@@ -3564,6 +3596,12 @@ var HttpTransport = class {
|
|
|
3564
3596
|
signUp(req, signal) {
|
|
3565
3597
|
return this.call({ method: "POST", path: "/v1/agent/sign-up", body: req, signal });
|
|
3566
3598
|
}
|
|
3599
|
+
activationStatus(signal) {
|
|
3600
|
+
return this.call({ method: "GET", path: "/v1/agent/activation", signal });
|
|
3601
|
+
}
|
|
3602
|
+
correctActivationEmail(human_email, revision, signal) {
|
|
3603
|
+
return this.call({ method: "PATCH", path: "/v1/agent/activation", body: { human_email, revision }, signal });
|
|
3604
|
+
}
|
|
3567
3605
|
verify(req, signal) {
|
|
3568
3606
|
return this.call({ method: "POST", path: "/v1/agent/verify", body: req, signal });
|
|
3569
3607
|
}
|
|
@@ -4196,6 +4234,12 @@ var MockTransport = class {
|
|
|
4196
4234
|
async signUp(req) {
|
|
4197
4235
|
return this.backend.signUp(req);
|
|
4198
4236
|
}
|
|
4237
|
+
async activationStatus() {
|
|
4238
|
+
return this.backend.activationStatus();
|
|
4239
|
+
}
|
|
4240
|
+
async correctActivationEmail(email, revision) {
|
|
4241
|
+
return this.backend.correctActivationEmail(email, revision);
|
|
4242
|
+
}
|
|
4199
4243
|
async verify(req) {
|
|
4200
4244
|
return this.backend.verify(req);
|
|
4201
4245
|
}
|
|
@@ -5739,6 +5783,12 @@ var ExtrovertClient = class _ExtrovertClient {
|
|
|
5739
5783
|
* Pending verification is also fail-closed with 403 `signup_disabled` while
|
|
5740
5784
|
* free signup is paused.
|
|
5741
5785
|
*/
|
|
5786
|
+
activationStatus(signal) {
|
|
5787
|
+
return this.transport.activationStatus(signal);
|
|
5788
|
+
}
|
|
5789
|
+
correctActivationEmail(human_email, revision, signal) {
|
|
5790
|
+
return this.transport.correctActivationEmail(human_email, revision, signal);
|
|
5791
|
+
}
|
|
5742
5792
|
verify(req, signal) {
|
|
5743
5793
|
return this.transport.verify(req, signal);
|
|
5744
5794
|
}
|
|
@@ -5906,7 +5956,7 @@ async function signWebhook(secret, body, timestampSeconds) {
|
|
|
5906
5956
|
}
|
|
5907
5957
|
|
|
5908
5958
|
// src/contract.ts
|
|
5909
|
-
var CONTRACT_VERSION = "0.1.0-pre.
|
|
5959
|
+
var CONTRACT_VERSION = "0.1.0-pre.17";
|
|
5910
5960
|
var CONTRACT_MANIFEST = {
|
|
5911
5961
|
name: "extrovert.review-loop",
|
|
5912
5962
|
version: CONTRACT_VERSION,
|
|
@@ -5982,6 +6032,26 @@ var CONTRACT_MANIFEST = {
|
|
|
5982
6032
|
skills: ["extrovert-send-email", "extrovert-writing-rules"]
|
|
5983
6033
|
};
|
|
5984
6034
|
|
|
6035
|
+
// src/storage.ts
|
|
6036
|
+
function storageWarningFromHeaders(headers) {
|
|
6037
|
+
if (headers.get("x-extrovert-storage-status") !== "available") return;
|
|
6038
|
+
const threshold = Number(headers.get("x-extrovert-storage-threshold"));
|
|
6039
|
+
if (!headers.has("x-extrovert-storage-used-bytes") || !headers.has("x-extrovert-storage-limit-bytes")) return;
|
|
6040
|
+
const used = Number(headers.get("x-extrovert-storage-used-bytes"));
|
|
6041
|
+
const limit = Number(headers.get("x-extrovert-storage-limit-bytes"));
|
|
6042
|
+
if (![90, 95, 99, 100].includes(threshold) || !Number.isSafeInteger(used) || used < 0 || !Number.isSafeInteger(limit) || limit < 0) return;
|
|
6043
|
+
const link = (name) => {
|
|
6044
|
+
const raw = headers.get(name);
|
|
6045
|
+
if (!raw || raw.length > 2048) return;
|
|
6046
|
+
try {
|
|
6047
|
+
const url = new URL(raw);
|
|
6048
|
+
if (url.protocol === "https:" && !url.username && !url.password) return url.href;
|
|
6049
|
+
} catch {
|
|
6050
|
+
}
|
|
6051
|
+
};
|
|
6052
|
+
return { threshold, used_bytes: used, limit_bytes: limit, cleanup_url: link("x-extrovert-storage-cleanup-url"), billing_url: link("x-extrovert-storage-billing-url") };
|
|
6053
|
+
}
|
|
6054
|
+
|
|
5985
6055
|
exports.ADMINISTRATIVE_FIXTURE_KEY = ADMINISTRATIVE_FIXTURE_KEY;
|
|
5986
6056
|
exports.API_VERSION_HEADER = API_VERSION_HEADER;
|
|
5987
6057
|
exports.Administration = Administration;
|
|
@@ -6049,6 +6119,7 @@ exports.reviewIdOf = reviewIdOf;
|
|
|
6049
6119
|
exports.sentMessageIdOf = sentMessageIdOf;
|
|
6050
6120
|
exports.serializeInclude = serializeInclude;
|
|
6051
6121
|
exports.signWebhook = signWebhook;
|
|
6122
|
+
exports.storageWarningFromHeaders = storageWarningFromHeaders;
|
|
6052
6123
|
exports.threadIdOf = threadIdOf;
|
|
6053
6124
|
exports.tierAllowsOrgWildcard = tierAllowsOrgWildcard;
|
|
6054
6125
|
exports.tierNeedsExplicitBreadth = tierNeedsExplicitBreadth;
|