@stardeck-customer-apps/testing 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md CHANGED
@@ -530,8 +530,13 @@ cursor, limit })`; `list()` intentionally keeps its previous array shape.
530
530
  production) or `app.starlens.reject("not a receipt")` (the 422 the SDK maps to
531
531
  `UnsupportedDocumentError`). An unregistered call fails with a descriptive 502 so a
532
532
  test never passes on an invented extraction. `app.starlens.calls` records each
533
- request's version, input names/media types (never bytes), schema and
534
- instructions — assert your `.describe()` aliases reached the wire there.
533
+ request's version, effort, input names/media types (never bytes), schema and
534
+ instructions — assert your `.describe()` aliases and `effort: "high"` retries
535
+ reached the wire there. `version: "v1"` with `effort: "high"` is refused with the
536
+ same 400 `unsupported_effort` as production (the SDK throws `ValidationError`). A
537
+ high request with no image input answers `effort: "low"` as production does;
538
+ pass `effort: "low"` in `app.starlens.mock(...)` to simulate an image production
539
+ could not decode.
535
540
 
536
541
  ### Receipt layout and printer capabilities
537
542
 
package/dist/index.d.mts CHANGED
@@ -536,7 +536,10 @@ interface TestEdge {
536
536
  }
537
537
  /** One Starlens request the app made, as the simulator saw it (names only, never bytes). */
538
538
  interface CapturedStarlensCall {
539
+ /** As sent (`latest` stays `latest`). */
539
540
  version: string;
541
+ /** As requested; `"low"` when the app did not set one. The reply says what ran. */
542
+ effort: "low" | "high";
540
543
  inputs: {
541
544
  name: string;
542
545
  mediaType: string | null;
@@ -557,6 +560,12 @@ type StarlensReply = {
557
560
  path: string;
558
561
  reason: string;
559
562
  }[];
563
+ /**
564
+ * The effort the reply says ran. Defaults to the requested effort, or `"low"` for a
565
+ * high request with no image input (production cannot crop a PDF, audio or video).
566
+ * Set `"low"` to simulate a high request on an image production could not decode.
567
+ */
568
+ effort?: "low" | "high";
560
569
  } | {
561
570
  reject: string;
562
571
  };
package/dist/index.d.ts CHANGED
@@ -536,7 +536,10 @@ interface TestEdge {
536
536
  }
537
537
  /** One Starlens request the app made, as the simulator saw it (names only, never bytes). */
538
538
  interface CapturedStarlensCall {
539
+ /** As sent (`latest` stays `latest`). */
539
540
  version: string;
541
+ /** As requested; `"low"` when the app did not set one. The reply says what ran. */
542
+ effort: "low" | "high";
540
543
  inputs: {
541
544
  name: string;
542
545
  mediaType: string | null;
@@ -557,6 +560,12 @@ type StarlensReply = {
557
560
  path: string;
558
561
  reason: string;
559
562
  }[];
563
+ /**
564
+ * The effort the reply says ran. Defaults to the requested effort, or `"low"` for a
565
+ * high request with no image input (production cannot crop a PDF, audio or video).
566
+ * Set `"low"` to simulate a high request on an image production could not decode.
567
+ */
568
+ effort?: "low" | "high";
560
569
  } | {
561
570
  reject: string;
562
571
  };
package/dist/index.js CHANGED
@@ -3102,6 +3102,7 @@ function createEdge() {
3102
3102
  }
3103
3103
 
3104
3104
  // src/simulator/starlens.ts
3105
+ var LATEST_VERSION = "v2";
3105
3106
  function starlensFailure(error, status, code) {
3106
3107
  return json({ success: false, error, code }, status);
3107
3108
  }
@@ -3120,11 +3121,18 @@ function nullFlagged(output, issues) {
3120
3121
  }
3121
3122
  return copy;
3122
3123
  }
3123
- async function handleStarlensExtract(request, signedDeploymentId) {
3124
- const body = await readJsonBody(request);
3125
- if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
3126
- return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
3127
- }
3124
+ function isInputShape(input) {
3125
+ if (!input || typeof input !== "object") return false;
3126
+ const i = input;
3127
+ return typeof i.url === "string" || typeof i.data === "string" && i.data.length > 0 && typeof i.mediaType === "string";
3128
+ }
3129
+ var NON_IMAGE_EXTENSION = /\.(pdf|mp3|m4a|wav|ogg|aac|flac|mp4|mov|webm|mkv)(\?|#|$)/i;
3130
+ function isCroppable(input) {
3131
+ if (typeof input.mediaType === "string") return input.mediaType.startsWith("image/");
3132
+ const name = typeof input.filename === "string" ? input.filename : input.url;
3133
+ return !(typeof name === "string" && NON_IMAGE_EXTENSION.test(name));
3134
+ }
3135
+ function validateStarlensBody(body) {
3128
3136
  const inputs = Array.isArray(body.inputs) ? body.inputs : [];
3129
3137
  if (inputs.length === 0) {
3130
3138
  return starlensFailure(
@@ -3133,6 +3141,13 @@ async function handleStarlensExtract(request, signedDeploymentId) {
3133
3141
  "VALIDATION_ERROR"
3134
3142
  );
3135
3143
  }
3144
+ if (!inputs.every(isInputShape)) {
3145
+ return starlensFailure(
3146
+ "Validation failed \u2014 inputs: each input needs a url, or data with a mediaType",
3147
+ 400,
3148
+ "VALIDATION_ERROR"
3149
+ );
3150
+ }
3136
3151
  const schema = body.schema;
3137
3152
  if (!schema || schema.type !== "object" || typeof schema.properties !== "object") {
3138
3153
  return starlensFailure(
@@ -3141,8 +3156,35 @@ async function handleStarlensExtract(request, signedDeploymentId) {
3141
3156
  "VALIDATION_ERROR"
3142
3157
  );
3143
3158
  }
3159
+ const version = body.version ?? "latest";
3160
+ if (version !== "v1" && version !== "v2" && version !== "latest") {
3161
+ return starlensFailure("Validation failed \u2014 version: unknown version", 400, "VALIDATION_ERROR");
3162
+ }
3163
+ const effort = body.effort ?? "low";
3164
+ if (effort !== "low" && effort !== "high") {
3165
+ return starlensFailure("Validation failed \u2014 effort: low or high", 400, "VALIDATION_ERROR");
3166
+ }
3167
+ const resolved = version === "latest" ? LATEST_VERSION : version;
3168
+ if (effort === "high" && resolved === "v1") {
3169
+ return starlensFailure(
3170
+ `Starlens v1 does not support effort "high"; use version "v2"`,
3171
+ 400,
3172
+ "unsupported_effort"
3173
+ );
3174
+ }
3175
+ return { version, resolved, effort, inputs, schema };
3176
+ }
3177
+ async function handleStarlensExtract(request, signedDeploymentId) {
3178
+ const body = await readJsonBody(request);
3179
+ const valid = validateStarlensBody(body);
3180
+ if (valid instanceof Response) return valid;
3181
+ const { version, resolved, effort, inputs, schema } = valid;
3182
+ if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
3183
+ return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
3184
+ }
3144
3185
  const call = {
3145
- version: typeof body.version === "string" ? body.version : "latest",
3186
+ version,
3187
+ effort,
3146
3188
  inputs: inputs.map((i) => ({
3147
3189
  name: typeof i.filename === "string" ? i.filename : typeof i.url === "string" ? i.url : "upload",
3148
3190
  mediaType: typeof i.mediaType === "string" ? i.mediaType : null,
@@ -3164,8 +3206,10 @@ async function handleStarlensExtract(request, signedDeploymentId) {
3164
3206
  return starlensFailure(reply.reject, 422, "unsupported_document");
3165
3207
  }
3166
3208
  const issues = reply.issues ?? [];
3209
+ const ran = reply.effort ?? (effort === "high" && !inputs.some(isCroppable) ? "low" : effort);
3167
3210
  return success({
3168
- version: call.version === "latest" ? "v1" : call.version,
3211
+ version: resolved,
3212
+ effort: ran,
3169
3213
  output: nullFlagged(reply.output, issues),
3170
3214
  issues,
3171
3215
  usage: { inputTokens: 0, outputTokens: 0, cost: 0 }
package/dist/index.mjs CHANGED
@@ -3063,6 +3063,7 @@ function createEdge() {
3063
3063
  }
3064
3064
 
3065
3065
  // src/simulator/starlens.ts
3066
+ var LATEST_VERSION = "v2";
3066
3067
  function starlensFailure(error, status, code) {
3067
3068
  return json({ success: false, error, code }, status);
3068
3069
  }
@@ -3081,11 +3082,18 @@ function nullFlagged(output, issues) {
3081
3082
  }
3082
3083
  return copy;
3083
3084
  }
3084
- async function handleStarlensExtract(request, signedDeploymentId) {
3085
- const body = await readJsonBody(request);
3086
- if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
3087
- return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
3088
- }
3085
+ function isInputShape(input) {
3086
+ if (!input || typeof input !== "object") return false;
3087
+ const i = input;
3088
+ return typeof i.url === "string" || typeof i.data === "string" && i.data.length > 0 && typeof i.mediaType === "string";
3089
+ }
3090
+ var NON_IMAGE_EXTENSION = /\.(pdf|mp3|m4a|wav|ogg|aac|flac|mp4|mov|webm|mkv)(\?|#|$)/i;
3091
+ function isCroppable(input) {
3092
+ if (typeof input.mediaType === "string") return input.mediaType.startsWith("image/");
3093
+ const name = typeof input.filename === "string" ? input.filename : input.url;
3094
+ return !(typeof name === "string" && NON_IMAGE_EXTENSION.test(name));
3095
+ }
3096
+ function validateStarlensBody(body) {
3089
3097
  const inputs = Array.isArray(body.inputs) ? body.inputs : [];
3090
3098
  if (inputs.length === 0) {
3091
3099
  return starlensFailure(
@@ -3094,6 +3102,13 @@ async function handleStarlensExtract(request, signedDeploymentId) {
3094
3102
  "VALIDATION_ERROR"
3095
3103
  );
3096
3104
  }
3105
+ if (!inputs.every(isInputShape)) {
3106
+ return starlensFailure(
3107
+ "Validation failed \u2014 inputs: each input needs a url, or data with a mediaType",
3108
+ 400,
3109
+ "VALIDATION_ERROR"
3110
+ );
3111
+ }
3097
3112
  const schema = body.schema;
3098
3113
  if (!schema || schema.type !== "object" || typeof schema.properties !== "object") {
3099
3114
  return starlensFailure(
@@ -3102,8 +3117,35 @@ async function handleStarlensExtract(request, signedDeploymentId) {
3102
3117
  "VALIDATION_ERROR"
3103
3118
  );
3104
3119
  }
3120
+ const version = body.version ?? "latest";
3121
+ if (version !== "v1" && version !== "v2" && version !== "latest") {
3122
+ return starlensFailure("Validation failed \u2014 version: unknown version", 400, "VALIDATION_ERROR");
3123
+ }
3124
+ const effort = body.effort ?? "low";
3125
+ if (effort !== "low" && effort !== "high") {
3126
+ return starlensFailure("Validation failed \u2014 effort: low or high", 400, "VALIDATION_ERROR");
3127
+ }
3128
+ const resolved = version === "latest" ? LATEST_VERSION : version;
3129
+ if (effort === "high" && resolved === "v1") {
3130
+ return starlensFailure(
3131
+ `Starlens v1 does not support effort "high"; use version "v2"`,
3132
+ 400,
3133
+ "unsupported_effort"
3134
+ );
3135
+ }
3136
+ return { version, resolved, effort, inputs, schema };
3137
+ }
3138
+ async function handleStarlensExtract(request, signedDeploymentId) {
3139
+ const body = await readJsonBody(request);
3140
+ const valid = validateStarlensBody(body);
3141
+ if (valid instanceof Response) return valid;
3142
+ const { version, resolved, effort, inputs, schema } = valid;
3143
+ if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
3144
+ return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
3145
+ }
3105
3146
  const call = {
3106
- version: typeof body.version === "string" ? body.version : "latest",
3147
+ version,
3148
+ effort,
3107
3149
  inputs: inputs.map((i) => ({
3108
3150
  name: typeof i.filename === "string" ? i.filename : typeof i.url === "string" ? i.url : "upload",
3109
3151
  mediaType: typeof i.mediaType === "string" ? i.mediaType : null,
@@ -3125,8 +3167,10 @@ async function handleStarlensExtract(request, signedDeploymentId) {
3125
3167
  return starlensFailure(reply.reject, 422, "unsupported_document");
3126
3168
  }
3127
3169
  const issues = reply.issues ?? [];
3170
+ const ran = reply.effort ?? (effort === "high" && !inputs.some(isCroppable) ? "low" : effort);
3128
3171
  return success({
3129
- version: call.version === "latest" ? "v1" : call.version,
3172
+ version: resolved,
3173
+ effort: ran,
3130
3174
  output: nullFlagged(reply.output, issues),
3131
3175
  issues,
3132
3176
  usage: { inputTokens: 0, outputTokens: 0, cost: 0 }
package/dist/setup.js CHANGED
@@ -2247,6 +2247,7 @@ async function handleEdgeRequest(request, subPath) {
2247
2247
  }
2248
2248
 
2249
2249
  // src/simulator/starlens.ts
2250
+ var LATEST_VERSION = "v2";
2250
2251
  function starlensFailure(error, status, code) {
2251
2252
  return json({ success: false, error, code }, status);
2252
2253
  }
@@ -2265,11 +2266,18 @@ function nullFlagged(output, issues) {
2265
2266
  }
2266
2267
  return copy;
2267
2268
  }
2268
- async function handleStarlensExtract(request, signedDeploymentId) {
2269
- const body = await readJsonBody(request);
2270
- if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
2271
- return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
2272
- }
2269
+ function isInputShape(input) {
2270
+ if (!input || typeof input !== "object") return false;
2271
+ const i = input;
2272
+ return typeof i.url === "string" || typeof i.data === "string" && i.data.length > 0 && typeof i.mediaType === "string";
2273
+ }
2274
+ var NON_IMAGE_EXTENSION = /\.(pdf|mp3|m4a|wav|ogg|aac|flac|mp4|mov|webm|mkv)(\?|#|$)/i;
2275
+ function isCroppable(input) {
2276
+ if (typeof input.mediaType === "string") return input.mediaType.startsWith("image/");
2277
+ const name = typeof input.filename === "string" ? input.filename : input.url;
2278
+ return !(typeof name === "string" && NON_IMAGE_EXTENSION.test(name));
2279
+ }
2280
+ function validateStarlensBody(body) {
2273
2281
  const inputs = Array.isArray(body.inputs) ? body.inputs : [];
2274
2282
  if (inputs.length === 0) {
2275
2283
  return starlensFailure(
@@ -2278,6 +2286,13 @@ async function handleStarlensExtract(request, signedDeploymentId) {
2278
2286
  "VALIDATION_ERROR"
2279
2287
  );
2280
2288
  }
2289
+ if (!inputs.every(isInputShape)) {
2290
+ return starlensFailure(
2291
+ "Validation failed \u2014 inputs: each input needs a url, or data with a mediaType",
2292
+ 400,
2293
+ "VALIDATION_ERROR"
2294
+ );
2295
+ }
2281
2296
  const schema = body.schema;
2282
2297
  if (!schema || schema.type !== "object" || typeof schema.properties !== "object") {
2283
2298
  return starlensFailure(
@@ -2286,8 +2301,35 @@ async function handleStarlensExtract(request, signedDeploymentId) {
2286
2301
  "VALIDATION_ERROR"
2287
2302
  );
2288
2303
  }
2304
+ const version = body.version ?? "latest";
2305
+ if (version !== "v1" && version !== "v2" && version !== "latest") {
2306
+ return starlensFailure("Validation failed \u2014 version: unknown version", 400, "VALIDATION_ERROR");
2307
+ }
2308
+ const effort = body.effort ?? "low";
2309
+ if (effort !== "low" && effort !== "high") {
2310
+ return starlensFailure("Validation failed \u2014 effort: low or high", 400, "VALIDATION_ERROR");
2311
+ }
2312
+ const resolved = version === "latest" ? LATEST_VERSION : version;
2313
+ if (effort === "high" && resolved === "v1") {
2314
+ return starlensFailure(
2315
+ `Starlens v1 does not support effort "high"; use version "v2"`,
2316
+ 400,
2317
+ "unsupported_effort"
2318
+ );
2319
+ }
2320
+ return { version, resolved, effort, inputs, schema };
2321
+ }
2322
+ async function handleStarlensExtract(request, signedDeploymentId) {
2323
+ const body = await readJsonBody(request);
2324
+ const valid = validateStarlensBody(body);
2325
+ if (valid instanceof Response) return valid;
2326
+ const { version, resolved, effort, inputs, schema } = valid;
2327
+ if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
2328
+ return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
2329
+ }
2289
2330
  const call = {
2290
- version: typeof body.version === "string" ? body.version : "latest",
2331
+ version,
2332
+ effort,
2291
2333
  inputs: inputs.map((i) => ({
2292
2334
  name: typeof i.filename === "string" ? i.filename : typeof i.url === "string" ? i.url : "upload",
2293
2335
  mediaType: typeof i.mediaType === "string" ? i.mediaType : null,
@@ -2309,8 +2351,10 @@ async function handleStarlensExtract(request, signedDeploymentId) {
2309
2351
  return starlensFailure(reply.reject, 422, "unsupported_document");
2310
2352
  }
2311
2353
  const issues = reply.issues ?? [];
2354
+ const ran = reply.effort ?? (effort === "high" && !inputs.some(isCroppable) ? "low" : effort);
2312
2355
  return success({
2313
- version: call.version === "latest" ? "v1" : call.version,
2356
+ version: resolved,
2357
+ effort: ran,
2314
2358
  output: nullFlagged(reply.output, issues),
2315
2359
  issues,
2316
2360
  usage: { inputTokens: 0, outputTokens: 0, cost: 0 }
package/dist/setup.mjs CHANGED
@@ -2223,6 +2223,7 @@ async function handleEdgeRequest(request, subPath) {
2223
2223
  }
2224
2224
 
2225
2225
  // src/simulator/starlens.ts
2226
+ var LATEST_VERSION = "v2";
2226
2227
  function starlensFailure(error, status, code) {
2227
2228
  return json({ success: false, error, code }, status);
2228
2229
  }
@@ -2241,11 +2242,18 @@ function nullFlagged(output, issues) {
2241
2242
  }
2242
2243
  return copy;
2243
2244
  }
2244
- async function handleStarlensExtract(request, signedDeploymentId) {
2245
- const body = await readJsonBody(request);
2246
- if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
2247
- return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
2248
- }
2245
+ function isInputShape(input) {
2246
+ if (!input || typeof input !== "object") return false;
2247
+ const i = input;
2248
+ return typeof i.url === "string" || typeof i.data === "string" && i.data.length > 0 && typeof i.mediaType === "string";
2249
+ }
2250
+ var NON_IMAGE_EXTENSION = /\.(pdf|mp3|m4a|wav|ogg|aac|flac|mp4|mov|webm|mkv)(\?|#|$)/i;
2251
+ function isCroppable(input) {
2252
+ if (typeof input.mediaType === "string") return input.mediaType.startsWith("image/");
2253
+ const name = typeof input.filename === "string" ? input.filename : input.url;
2254
+ return !(typeof name === "string" && NON_IMAGE_EXTENSION.test(name));
2255
+ }
2256
+ function validateStarlensBody(body) {
2249
2257
  const inputs = Array.isArray(body.inputs) ? body.inputs : [];
2250
2258
  if (inputs.length === 0) {
2251
2259
  return starlensFailure(
@@ -2254,6 +2262,13 @@ async function handleStarlensExtract(request, signedDeploymentId) {
2254
2262
  "VALIDATION_ERROR"
2255
2263
  );
2256
2264
  }
2265
+ if (!inputs.every(isInputShape)) {
2266
+ return starlensFailure(
2267
+ "Validation failed \u2014 inputs: each input needs a url, or data with a mediaType",
2268
+ 400,
2269
+ "VALIDATION_ERROR"
2270
+ );
2271
+ }
2257
2272
  const schema = body.schema;
2258
2273
  if (!schema || schema.type !== "object" || typeof schema.properties !== "object") {
2259
2274
  return starlensFailure(
@@ -2262,8 +2277,35 @@ async function handleStarlensExtract(request, signedDeploymentId) {
2262
2277
  "VALIDATION_ERROR"
2263
2278
  );
2264
2279
  }
2280
+ const version = body.version ?? "latest";
2281
+ if (version !== "v1" && version !== "v2" && version !== "latest") {
2282
+ return starlensFailure("Validation failed \u2014 version: unknown version", 400, "VALIDATION_ERROR");
2283
+ }
2284
+ const effort = body.effort ?? "low";
2285
+ if (effort !== "low" && effort !== "high") {
2286
+ return starlensFailure("Validation failed \u2014 effort: low or high", 400, "VALIDATION_ERROR");
2287
+ }
2288
+ const resolved = version === "latest" ? LATEST_VERSION : version;
2289
+ if (effort === "high" && resolved === "v1") {
2290
+ return starlensFailure(
2291
+ `Starlens v1 does not support effort "high"; use version "v2"`,
2292
+ 400,
2293
+ "unsupported_effort"
2294
+ );
2295
+ }
2296
+ return { version, resolved, effort, inputs, schema };
2297
+ }
2298
+ async function handleStarlensExtract(request, signedDeploymentId) {
2299
+ const body = await readJsonBody(request);
2300
+ const valid = validateStarlensBody(body);
2301
+ if (valid instanceof Response) return valid;
2302
+ const { version, resolved, effort, inputs, schema } = valid;
2303
+ if (signedDeploymentId !== null && body.deploymentId !== signedDeploymentId) {
2304
+ return starlensFailure("Deployment ID mismatch", 401, "AUTHENTICATION_ERROR");
2305
+ }
2265
2306
  const call = {
2266
- version: typeof body.version === "string" ? body.version : "latest",
2307
+ version,
2308
+ effort,
2267
2309
  inputs: inputs.map((i) => ({
2268
2310
  name: typeof i.filename === "string" ? i.filename : typeof i.url === "string" ? i.url : "upload",
2269
2311
  mediaType: typeof i.mediaType === "string" ? i.mediaType : null,
@@ -2285,8 +2327,10 @@ async function handleStarlensExtract(request, signedDeploymentId) {
2285
2327
  return starlensFailure(reply.reject, 422, "unsupported_document");
2286
2328
  }
2287
2329
  const issues = reply.issues ?? [];
2330
+ const ran = reply.effort ?? (effort === "high" && !inputs.some(isCroppable) ? "low" : effort);
2288
2331
  return success({
2289
- version: call.version === "latest" ? "v1" : call.version,
2332
+ version: resolved,
2333
+ effort: ran,
2290
2334
  output: nullFlagged(reply.output, issues),
2291
2335
  issues,
2292
2336
  usage: { inputTokens: 0, outputTokens: 0, cost: 0 }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stardeck-customer-apps/testing",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "Vitest test harness for Stardeck customer apps — in-process Postgres (PGlite) plus a control-plane simulator so the real Stardeck SDKs run unmodified in tests",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",