@happyvertical/smrt-agents 0.51.2 → 0.51.4
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/AGENTS.md +1 -0
- package/README.md +62 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +553 -4
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/sveltekit-data-surface-routes.d.ts +42 -0
- package/dist/server/sveltekit-data-surface-routes.d.ts.map +1 -0
- package/dist/server.js +142 -1
- package/dist/server.js.map +1 -1
- package/dist/smrt-collection-data-surface.d.ts +136 -0
- package/dist/smrt-collection-data-surface.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +5 -5
- package/package.json +18 -18
package/dist/manifest.json
CHANGED
package/dist/server/index.d.ts
CHANGED
|
@@ -36,4 +36,5 @@ export { createJobsDataSurfaceBackgroundQueue, registerDataSurfaceBackgroundActi
|
|
|
36
36
|
export { extractAgentManifest, extractAgentPackagesFromConfig, loadManifestsFromConfig, loadManifestsFromPackages, type PackageManifest, } from './manifest-utils.js';
|
|
37
37
|
export { type SerializedAgent, serializeResolvedAgent, } from './serialization.js';
|
|
38
38
|
export { createSqlDataSurfaceActionStateStore, DataSurfaceActionIdempotencyState, DataSurfaceActionStateCorruptionError, DataSurfaceActionTokenState, type DataSurfaceIdempotencyRecoveryRequest, SqlDataSurfaceActionStateStore, type SqlDataSurfaceActionStateStoreOptions, } from './sql-data-surface-action-state.js';
|
|
39
|
+
export { createDataSurfaceActionRouteHandlers, type DataSurfaceBulkSelectionResolver, type DataSurfaceRouteHandlerOptions, type DataSurfaceRouteHandlers, type DataSurfaceRoutePrincipalResolver, resolveBulkExplicitIds, } from './sveltekit-data-surface-routes.js';
|
|
39
40
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,YAAY,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,KAAK,gBAAgB,EACrB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,8BAA8B,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,IAAI,8BAA8B,EAC/D,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EACvC,KAAK,2BAA2B,EAChC,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EAClC,KAAK,qCAAqC,EAC1C,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,EAC3C,KAAK,iCAAiC,EACtC,KAAK,6BAA6B,EAClC,KAAK,iCAAiC,EACtC,KAAK,8BAA8B,EACnC,mCAAmC,EACnC,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,GAClC,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,wBAAwB,EACxB,qCAAqC,GACtC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,oCAAoC,EACpC,0CAA0C,EAC1C,yBAAyB,GAC1B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,uBAAuB,EACvB,yBAAyB,EACzB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,eAAe,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oCAAoC,EACpC,iCAAiC,EACjC,qCAAqC,EACrC,2BAA2B,EAC3B,KAAK,qCAAqC,EAC1C,8BAA8B,EAC9B,KAAK,qCAAqC,GAC3C,MAAM,oCAAoC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,YAAY,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,KAAK,gBAAgB,EACrB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,8BAA8B,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,IAAI,8BAA8B,EAC/D,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EACvC,KAAK,2BAA2B,EAChC,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EAClC,KAAK,qCAAqC,EAC1C,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,EAC3C,KAAK,iCAAiC,EACtC,KAAK,6BAA6B,EAClC,KAAK,iCAAiC,EACtC,KAAK,8BAA8B,EACnC,mCAAmC,EACnC,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,4BAA4B,GAClC,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,wBAAwB,EACxB,qCAAqC,GACtC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,oCAAoC,EACpC,0CAA0C,EAC1C,yBAAyB,GAC1B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,uBAAuB,EACvB,yBAAyB,EACzB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,eAAe,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oCAAoC,EACpC,iCAAiC,EACjC,qCAAqC,EACrC,2BAA2B,EAC3B,KAAK,qCAAqC,EAC1C,8BAA8B,EAC9B,KAAK,qCAAqC,GAC3C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,oCAAoC,EACpC,KAAK,gCAAgC,EACrC,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EACtC,sBAAsB,GACvB,MAAM,oCAAoC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DataSurfaceRowId } from '@happyvertical/smrt-types';
|
|
2
|
+
import { ExecuteAsPrincipalOptions } from '../execute-as-principal.js';
|
|
3
|
+
import { DataSurfaceActionAdapter } from './data-surface-actions.js';
|
|
4
|
+
/** Resolves the bound principal for one incoming request. Throw to refuse. */
|
|
5
|
+
export type DataSurfaceRoutePrincipalResolver = (request: Request) => ExecuteAsPrincipalOptions | Promise<ExecuteAsPrincipalOptions>;
|
|
6
|
+
export interface DataSurfaceRouteHandlerOptions {
|
|
7
|
+
adapter: DataSurfaceActionAdapter;
|
|
8
|
+
resolvePrincipal: DataSurfaceRoutePrincipalResolver;
|
|
9
|
+
/** Called when `resolvePrincipal` throws; defaults to logging nothing. */
|
|
10
|
+
onAuthError?(error: unknown, request: Request): void;
|
|
11
|
+
/** Overrides the shared `DATA_SURFACE_MAX_REQUEST_BYTES` transport ceiling. */
|
|
12
|
+
maxRequestBytes?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface DataSurfaceRouteHandlers {
|
|
15
|
+
/** Wire as `export const POST: RequestHandler = ({ request }) => handlers.preview(request)`. */
|
|
16
|
+
preview(request: Request): Promise<Response>;
|
|
17
|
+
apply(request: Request): Promise<Response>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build the preview/apply `Request -> Response` pair for one action surface.
|
|
21
|
+
* Principal/tenant resolution, idempotency, and durable queueing are entirely
|
|
22
|
+
* owned by `options.adapter` (from `createDataSurfaceActionAdapter`); this
|
|
23
|
+
* helper only bridges transport. Ordered deliberately: the request-byte cap
|
|
24
|
+
* is enforced from the `content-length` header before anything else runs
|
|
25
|
+
* (no buffering), then the principal is resolved (refusing before the body
|
|
26
|
+
* is ever parsed), then the body is read under the same cap as it streams,
|
|
27
|
+
* and only a resolved, in-budget request reaches the adapter.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createDataSurfaceActionRouteHandlers(options: DataSurfaceRouteHandlerOptions): DataSurfaceRouteHandlers;
|
|
30
|
+
/**
|
|
31
|
+
* Helper for the bulk-scope shape (e.g. "apply this look to every reference
|
|
32
|
+
* photo in the current selection"): resolves an `explicit-ids` selection to
|
|
33
|
+
* the full set of related row ids server-side, so the browser only ever
|
|
34
|
+
* supplies the anchor id(s) and the framework — not the app — is the source
|
|
35
|
+
* of truth for which rows a single idempotency key covers.
|
|
36
|
+
*/
|
|
37
|
+
export interface DataSurfaceBulkSelectionResolver {
|
|
38
|
+
/** Expand the browser-supplied anchor ids into the full row set to act on. */
|
|
39
|
+
expand(anchorRowIds: DataSurfaceRowId[]): Promise<DataSurfaceRowId[]> | DataSurfaceRowId[];
|
|
40
|
+
}
|
|
41
|
+
export declare function resolveBulkExplicitIds(anchorRowIds: DataSurfaceRowId[], resolver: DataSurfaceBulkSelectionResolver): Promise<DataSurfaceRowId[]>;
|
|
42
|
+
//# sourceMappingURL=sveltekit-data-surface-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-data-surface-routes.d.ts","sourceRoot":"","sources":["../../src/server/sveltekit-data-surface-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EACV,wBAAwB,EAEzB,MAAM,2BAA2B,CAAC;AAEnC,8EAA8E;AAC9E,MAAM,MAAM,iCAAiC,GAAG,CAC9C,OAAO,EAAE,OAAO,KACb,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;AAEpE,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,wBAAwB,CAAC;IAClC,gBAAgB,EAAE,iCAAiC,CAAC;IACpD,0EAA0E;IAC1E,WAAW,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACrD,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,gGAAgG;IAChG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5C;AA0HD;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,8BAA8B,GACtC,wBAAwB,CA2D1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gCAAgC;IAC/C,8EAA8E;IAC9E,MAAM,CACJ,YAAY,EAAE,gBAAgB,EAAE,GAC/B,OAAO,CAAC,gBAAgB,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC;CACrD;AAED,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,gBAAgB,EAAE,EAChC,QAAQ,EAAE,gCAAgC,GACzC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAW7B"}
|
package/dist/server.js
CHANGED
|
@@ -5,6 +5,7 @@ import { sanitizeConfig } from "@happyvertical/smrt-config";
|
|
|
5
5
|
import { TenantScoped, getTenantId, tenantId } from "@happyvertical/smrt-tenancy";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import { SmrtJobCollection, backgroundEligible, createHmacDurableJobPayloadSigner, getActiveJobExecutionContext, isRunnerExecutionContext } from "@happyvertical/smrt-jobs";
|
|
8
|
+
import { DATA_SURFACE_MAX_REQUEST_BYTES } from "@happyvertical/smrt-ui/data";
|
|
8
9
|
//#region src/server/api-routes.ts
|
|
9
10
|
function buildRouteMap(manifests) {
|
|
10
11
|
const routes = /* @__PURE__ */ new Map();
|
|
@@ -1062,6 +1063,146 @@ function emptyTokenRecord() {
|
|
|
1062
1063
|
};
|
|
1063
1064
|
}
|
|
1064
1065
|
//#endregion
|
|
1065
|
-
|
|
1066
|
+
//#region src/server/sveltekit-data-surface-routes.ts
|
|
1067
|
+
var REASON_STATUS = /* @__PURE__ */ new Map([
|
|
1068
|
+
["invalid_request", 400],
|
|
1069
|
+
["not_found", 404],
|
|
1070
|
+
["denied", 403],
|
|
1071
|
+
["unsupported", 404],
|
|
1072
|
+
["selection_not_supported", 400],
|
|
1073
|
+
["limit_exceeded", 413],
|
|
1074
|
+
["stale_revision", 409],
|
|
1075
|
+
["stale_preview", 409],
|
|
1076
|
+
["confirmation_required", 409],
|
|
1077
|
+
["confirmation_mismatch", 409],
|
|
1078
|
+
["confirmation_replayed", 409],
|
|
1079
|
+
["invalid_or_expired_confirmation", 409],
|
|
1080
|
+
["idempotency_conflict", 409],
|
|
1081
|
+
["idempotency_in_progress", 202],
|
|
1082
|
+
["background_unavailable", 503]
|
|
1083
|
+
]);
|
|
1084
|
+
function statusForResult(result) {
|
|
1085
|
+
if (result.ok) return 200;
|
|
1086
|
+
return REASON_STATUS.get(result.reason ?? "") ?? 422;
|
|
1087
|
+
}
|
|
1088
|
+
function authorizationErrorStatus(error) {
|
|
1089
|
+
if (!(error instanceof Error)) return void 0;
|
|
1090
|
+
const status = error.status;
|
|
1091
|
+
return typeof status === "number" && status >= 400 && status < 500 ? status : void 0;
|
|
1092
|
+
}
|
|
1093
|
+
function jsonResponse(body, status) {
|
|
1094
|
+
return new Response(JSON.stringify(body), {
|
|
1095
|
+
status,
|
|
1096
|
+
headers: { "content-type": "application/json" }
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
function declaredContentLengthExceeds(request, maxBytes) {
|
|
1100
|
+
const declared = request.headers.get("content-length");
|
|
1101
|
+
if (declared === null) return false;
|
|
1102
|
+
const bytes = Number(declared);
|
|
1103
|
+
return !Number.isFinite(bytes) || bytes > maxBytes;
|
|
1104
|
+
}
|
|
1105
|
+
async function readBoundedBody(request, maxBytes) {
|
|
1106
|
+
const stream = request.body;
|
|
1107
|
+
if (!stream) return {
|
|
1108
|
+
ok: true,
|
|
1109
|
+
text: await request.text()
|
|
1110
|
+
};
|
|
1111
|
+
const reader = stream.getReader();
|
|
1112
|
+
const chunks = [];
|
|
1113
|
+
let total = 0;
|
|
1114
|
+
for (;;) {
|
|
1115
|
+
let step;
|
|
1116
|
+
try {
|
|
1117
|
+
step = await reader.read();
|
|
1118
|
+
} catch {
|
|
1119
|
+
return {
|
|
1120
|
+
ok: false,
|
|
1121
|
+
reason: "invalid_request"
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
if (step.done || !step.value) break;
|
|
1125
|
+
total += step.value.byteLength;
|
|
1126
|
+
if (total > maxBytes) {
|
|
1127
|
+
await reader.cancel().catch(() => void 0);
|
|
1128
|
+
return {
|
|
1129
|
+
ok: false,
|
|
1130
|
+
reason: "payload_too_large"
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
chunks.push(step.value);
|
|
1134
|
+
}
|
|
1135
|
+
const merged = new Uint8Array(total);
|
|
1136
|
+
let offset = 0;
|
|
1137
|
+
for (const chunk of chunks) {
|
|
1138
|
+
merged.set(chunk, offset);
|
|
1139
|
+
offset += chunk.byteLength;
|
|
1140
|
+
}
|
|
1141
|
+
return {
|
|
1142
|
+
ok: true,
|
|
1143
|
+
text: new TextDecoder("utf-8").decode(merged)
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
function parseJson(text) {
|
|
1147
|
+
try {
|
|
1148
|
+
const parsed = JSON.parse(text);
|
|
1149
|
+
return parsed && typeof parsed === "object" ? parsed : void 0;
|
|
1150
|
+
} catch {
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
function createDataSurfaceActionRouteHandlers(options) {
|
|
1155
|
+
const { adapter, resolvePrincipal, onAuthError } = options;
|
|
1156
|
+
const maxRequestBytes = options.maxRequestBytes ?? DATA_SURFACE_MAX_REQUEST_BYTES;
|
|
1157
|
+
async function handle(request, phase) {
|
|
1158
|
+
if (declaredContentLengthExceeds(request, maxRequestBytes)) return jsonResponse({ error: "payload_too_large" }, 413);
|
|
1159
|
+
let principal;
|
|
1160
|
+
try {
|
|
1161
|
+
principal = await resolvePrincipal(request);
|
|
1162
|
+
} catch (error) {
|
|
1163
|
+
onAuthError?.(error, request);
|
|
1164
|
+
return jsonResponse({ error: "unauthorized" }, 401);
|
|
1165
|
+
}
|
|
1166
|
+
const bodyResult = await readBoundedBody(request, maxRequestBytes);
|
|
1167
|
+
if (!bodyResult.ok) return jsonResponse({ error: bodyResult.reason }, bodyResult.reason === "payload_too_large" ? 413 : 400);
|
|
1168
|
+
const body = parseJson(bodyResult.text);
|
|
1169
|
+
if (!body) return jsonResponse({ error: "invalid_request" }, 400);
|
|
1170
|
+
let result;
|
|
1171
|
+
try {
|
|
1172
|
+
result = phase === "preview" ? await adapter.preview(body, { principal }) : await adapter.apply(body, { principal });
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
const status = authorizationErrorStatus(error);
|
|
1175
|
+
if (status === void 0) throw error;
|
|
1176
|
+
return jsonResponse({
|
|
1177
|
+
version: 1,
|
|
1178
|
+
requestId: body.requestId,
|
|
1179
|
+
identity: body.identity,
|
|
1180
|
+
actionId: body.actionId,
|
|
1181
|
+
phase,
|
|
1182
|
+
ok: false,
|
|
1183
|
+
reason: "denied"
|
|
1184
|
+
}, status);
|
|
1185
|
+
}
|
|
1186
|
+
return jsonResponse(result, statusForResult(result));
|
|
1187
|
+
}
|
|
1188
|
+
return {
|
|
1189
|
+
preview: (request) => handle(request, "preview"),
|
|
1190
|
+
apply: (request) => handle(request, "apply")
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
async function resolveBulkExplicitIds(anchorRowIds, resolver) {
|
|
1194
|
+
const expanded = await resolver.expand(anchorRowIds);
|
|
1195
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1196
|
+
const unique = [];
|
|
1197
|
+
for (const rowId of expanded) {
|
|
1198
|
+
const key = `${typeof rowId}:${String(rowId)}`;
|
|
1199
|
+
if (seen.has(key)) continue;
|
|
1200
|
+
seen.add(key);
|
|
1201
|
+
unique.push(rowId);
|
|
1202
|
+
}
|
|
1203
|
+
return unique;
|
|
1204
|
+
}
|
|
1205
|
+
//#endregion
|
|
1206
|
+
export { DataSurfaceActionIdempotencyState, DataSurfaceActionStateCorruptionError, DataSurfaceActionTokenState, InMemoryDataSurfaceActionStateStore, SmrtDataSurfaceActionTask, SqlDataSurfaceActionStateStore, buildRouteMap, createDataSurfaceActionAdapter, createDataSurfaceActionRouteHandlers, createJobsDataSurfaceBackgroundQueue, createSqlDataSurfaceActionStateStore, extractAgentManifest, extractAgentPackagesFromConfig, isBoundedDataSurfaceJsonValue, loadManifestsFromConfig, loadManifestsFromPackages, loadSlotConfigs, registerDataSurfaceBackgroundActionHandler, resolveAPIRoute, resolveBulkExplicitIds, serializeResolvedAgent };
|
|
1066
1207
|
|
|
1067
1208
|
//# sourceMappingURL=server.js.map
|