@blotout/qinto-cli 0.1.4 → 0.1.5

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.
@@ -326,6 +326,56 @@ var newSpanId = /* @__PURE__ */ __name(() => {
326
326
  return randomHex(8);
327
327
  }, "newSpanId");
328
328
 
329
+ // ../../libs/tail-trace/src/redact.ts
330
+ var SENSITIVE_URL_PARAMS = /* @__PURE__ */ new Set([
331
+ "access_token",
332
+ "api_key",
333
+ "api_secret",
334
+ "client_secret",
335
+ "code",
336
+ "key",
337
+ "password",
338
+ "refresh_token",
339
+ "secret",
340
+ "session",
341
+ "session_id",
342
+ "token"
343
+ ]);
344
+ var PARAM_MATCHER = /(^|[?&])([^=&?\s]+)=[^&\s]*/g;
345
+ var redactUrlParams = /* @__PURE__ */ __name((value) => {
346
+ return value.replaceAll(PARAM_MATCHER, (match2, separator, param) => {
347
+ return SENSITIVE_URL_PARAMS.has(param.toLowerCase()) ? `${separator}${param}=[REDACTED]` : match2;
348
+ });
349
+ }, "redactUrlParams");
350
+ var mappedAttrs = /* @__PURE__ */ __name((attrs, redact) => {
351
+ const redacted = {};
352
+ for (const [key, value] of Object.entries(attrs)) {
353
+ redacted[key] = typeof value === "string" ? redact(value) : value;
354
+ }
355
+ return redacted;
356
+ }, "mappedAttrs");
357
+ var redactedEvent = /* @__PURE__ */ __name((event, redact) => {
358
+ return {
359
+ ...event,
360
+ name: redact(event.name),
361
+ ...event.attrs === void 0 ? {} : { attrs: mappedAttrs(event.attrs, redact) }
362
+ };
363
+ }, "redactedEvent");
364
+ var redactedSpan = /* @__PURE__ */ __name((span, redact) => {
365
+ return {
366
+ ...span,
367
+ name: redact(span.name),
368
+ ...span.attrs === void 0 ? {} : { attrs: mappedAttrs(span.attrs, redact) },
369
+ ...span.events === void 0 ? {} : { events: span.events.map((event) => redactedEvent(event, redact)) },
370
+ ...span.error === void 0 ? {} : { error: redact(span.error) }
371
+ };
372
+ }, "redactedSpan");
373
+ var redactSpans = /* @__PURE__ */ __name((spans, redact) => {
374
+ return spans.map((span) => {
375
+ return redactedSpan(span, redact);
376
+ });
377
+ }, "redactSpans");
378
+
329
379
  // ../../libs/tail-trace/src/scope.ts
330
380
  import { AsyncLocalStorage } from "node:async_hooks";
331
381
  var scopes = new AsyncLocalStorage();
@@ -382,7 +432,7 @@ var logRecord = /* @__PURE__ */ __name((record2) => {
382
432
  console.log(formatSpansRecord(record2));
383
433
  }, "logRecord");
384
434
  var runInvocation = /* @__PURE__ */ __name(async (input, run) => {
385
- const buffer = { spans: [], flushed: false };
435
+ const buffer = { spans: [], flushed: false, pending: [] };
386
436
  const traceId = input.trace?.traceId ?? newTraceId();
387
437
  const root = startSpan({ traceId, parent: input.trace?.parent, name: input.name, attrs: input.attrs });
388
438
  try {
@@ -393,10 +443,12 @@ var runInvocation = /* @__PURE__ */ __name(async (input, run) => {
393
443
  throw error51;
394
444
  } finally {
395
445
  root.end = Date.now();
446
+ await Promise.allSettled(buffer.pending);
396
447
  buffer.spans.push(root);
397
448
  buffer.flushed = true;
398
449
  const emit = input.emit ?? logRecord;
399
- emit(budgetSpans(buffer.spans, input.budget ?? MAX_SPANS_BYTES));
450
+ const spans = input.redact === void 0 ? buffer.spans : redactSpans(buffer.spans, input.redact);
451
+ emit(budgetSpans(spans, input.budget ?? MAX_SPANS_BYTES));
400
452
  }
401
453
  }, "runInvocation");
402
454
 
@@ -452,28 +504,6 @@ var parseDispatchTrace = /* @__PURE__ */ __name((header) => {
452
504
  };
453
505
  }, "parseDispatchTrace");
454
506
 
455
- // ../../libs/tail-trace/src/redact.ts
456
- var SENSITIVE_URL_PARAMS = /* @__PURE__ */ new Set([
457
- "access_token",
458
- "api_key",
459
- "api_secret",
460
- "client_secret",
461
- "code",
462
- "key",
463
- "password",
464
- "refresh_token",
465
- "secret",
466
- "session",
467
- "session_id",
468
- "token"
469
- ]);
470
- var PARAM_MATCHER = /(^|[?&])([^=&?\s]+)=[^&\s]*/g;
471
- var redactUrlParams = /* @__PURE__ */ __name((value) => {
472
- return value.replaceAll(PARAM_MATCHER, (match2, separator, param) => {
473
- return SENSITIVE_URL_PARAMS.has(param.toLowerCase()) ? `${separator}${param}=[REDACTED]` : match2;
474
- });
475
- }, "redactUrlParams");
476
-
477
507
  // ../../libs/tail-trace/src/trace.ts
478
508
  var traced = /* @__PURE__ */ __name(async (name, options, run) => {
479
509
  const scope = currentScope();
@@ -494,22 +524,22 @@ var traced = /* @__PURE__ */ __name(async (name, options, run) => {
494
524
  }
495
525
  }
496
526
  }, "traced");
497
- var liveSpan = /* @__PURE__ */ __name(() => {
527
+ var liveScope = /* @__PURE__ */ __name(() => {
498
528
  const scope = currentScope();
499
529
  if (scope === void 0 || scope.buffer.flushed) {
500
530
  return void 0;
501
531
  }
502
- return scope.span;
503
- }, "liveSpan");
532
+ return scope;
533
+ }, "liveScope");
504
534
  var setSpanAttributes = /* @__PURE__ */ __name((attrs) => {
505
- const span = liveSpan();
535
+ const span = liveScope()?.span;
506
536
  if (span === void 0) {
507
537
  return;
508
538
  }
509
539
  span.attrs = { ...span.attrs, ...attrs };
510
540
  }, "setSpanAttributes");
511
541
  var addSpanEvent = /* @__PURE__ */ __name((name, options = {}) => {
512
- const span = liveSpan();
542
+ const span = liveScope()?.span;
513
543
  if (span === void 0) {
514
544
  return;
515
545
  }
@@ -522,7 +552,7 @@ var addSpanEvent = /* @__PURE__ */ __name((name, options = {}) => {
522
552
  span.events = [...span.events ?? [], event];
523
553
  }, "addSpanEvent");
524
554
  var recordError = /* @__PURE__ */ __name((error51, attrs = {}) => {
525
- const span = liveSpan();
555
+ const span = liveScope()?.span;
526
556
  if (span === void 0) {
527
557
  return;
528
558
  }
@@ -15721,7 +15751,7 @@ var actionContextFields = {
15721
15751
  locale: external_exports.string().min(1).max(64).optional(),
15722
15752
  provenance: external_exports.enum(["edge", "caller"])
15723
15753
  }).strict().optional(),
15724
- session: external_exports.object({ id: external_exports.string().min(1).max(64), isNew: external_exports.boolean() }).strict().optional()
15754
+ session: external_exports.object({ id: external_exports.string().min(1).max(64), isNew: external_exports.boolean(), startedAt: external_exports.number().int().nonnegative().safe() }).strict().optional()
15725
15755
  };
15726
15756
  var actionContextSchema = external_exports.discriminatedUnion("source", [
15727
15757
  external_exports.object({ source: external_exports.literal("browser"), ...actionContextFields }).strict(),
@@ -15740,7 +15770,7 @@ var envelopeRequestSchema = external_exports.object({
15740
15770
  properties: external_exports.record(external_exports.string(), external_exports.unknown()),
15741
15771
  geo: external_exports.record(external_exports.string(), external_exports.string()).optional()
15742
15772
  }).strict(),
15743
- consent: external_exports.object({ categories: external_exports.record(external_exports.string(), external_exports.boolean()), apps: external_exports.record(external_exports.string(), external_exports.boolean()) }).strict().optional(),
15773
+ consent: external_exports.object({ enabled: external_exports.boolean(), categories: external_exports.record(external_exports.string(), external_exports.boolean()), apps: external_exports.record(external_exports.string(), external_exports.boolean()) }).strict().optional(),
15744
15774
  geo: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
15745
15775
  // Only what this app captured or wrote for this visitor; `updatedAt` is when the current value
15746
15776
  // was first seen, which is the click time a CAPI `fbc` is built from.
@@ -18185,6 +18215,18 @@ var FACT_KINDS = [
18185
18215
  "context_shared_kv",
18186
18216
  "context_shared_text"
18187
18217
  ];
18218
+ var APP_FACT_KINDS = [
18219
+ "custom",
18220
+ "attribution",
18221
+ "identifier",
18222
+ "conversion",
18223
+ "pii",
18224
+ "consent_category",
18225
+ "consent_app",
18226
+ "geo"
18227
+ ];
18228
+ var MAX_APP_FACTS_PER_PAGE = 100;
18229
+ var MAX_APP_FACT_PAGE_BYTES = 1024 * 1024;
18188
18230
  var COLUMNS = "kind, scope, key, value, source, amount, currency, event_id, data_json, first_at, observed_at, synced_at";
18189
18231
  var rowOf = /* @__PURE__ */ __name((row) => {
18190
18232
  return {
@@ -18202,6 +18244,47 @@ var rowOf = /* @__PURE__ */ __name((row) => {
18202
18244
  syncedAt: row.synced_at
18203
18245
  };
18204
18246
  }, "rowOf");
18247
+ var appFactOf = /* @__PURE__ */ __name((row) => {
18248
+ const { syncedAt: _syncedAt, ...fact } = rowOf(row);
18249
+ return { ...fact, kind: fact.kind };
18250
+ }, "appFactOf");
18251
+ var listAppFacts = /* @__PURE__ */ __name((sql, query) => {
18252
+ const maxRowId = query.maxRowId ?? sql.exec("SELECT MAX(rowid) AS maxRowId FROM facts").one().maxRowId;
18253
+ if (maxRowId === null) {
18254
+ return { items: [], next: null };
18255
+ }
18256
+ const where = ["rowid > ?", "rowid <= ?"];
18257
+ const params = [query.afterRowId, maxRowId];
18258
+ if (query.kinds.length > 0) {
18259
+ where.push(`kind IN (${query.kinds.map(() => "?").join(", ")})`);
18260
+ params.push(...query.kinds);
18261
+ }
18262
+ if (query.observedAtGte !== null) {
18263
+ where.push("observed_at >= ?");
18264
+ params.push(query.observedAtGte);
18265
+ }
18266
+ if (query.observedAtLt !== null) {
18267
+ where.push("observed_at < ?");
18268
+ params.push(query.observedAtLt);
18269
+ }
18270
+ const rows = sql.exec(`SELECT rowid, ${COLUMNS} FROM facts WHERE ${where.join(" AND ")} ORDER BY rowid LIMIT ?`, ...params, query.limit + 1).toArray();
18271
+ const items = [];
18272
+ let lastRowId = query.afterRowId;
18273
+ for (const row of rows.slice(0, query.limit)) {
18274
+ const fact = appFactOf(row);
18275
+ const candidate = [...items, fact];
18276
+ if (new TextEncoder().encode(JSON.stringify(candidate)).byteLength > MAX_APP_FACT_PAGE_BYTES) {
18277
+ if (items.length === 0) {
18278
+ throw new Error("fact_too_large");
18279
+ }
18280
+ break;
18281
+ }
18282
+ items.push(fact);
18283
+ lastRowId = row.rowid;
18284
+ }
18285
+ const hasMore = rows.length > items.length;
18286
+ return { items, next: hasMore ? { afterRowId: lastRowId, maxRowId } : null };
18287
+ }, "listAppFacts");
18205
18288
  var insertFact = /* @__PURE__ */ __name((sql, fact) => {
18206
18289
  sql.exec(
18207
18290
  `INSERT INTO facts (${COLUMNS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`,
@@ -19018,7 +19101,7 @@ var buildEnvelope = /* @__PURE__ */ __name((target, trigger, snapshot, context)
19018
19101
  },
19019
19102
  ...geoAllowed ? { geo: snapshot.userGeo } : {}
19020
19103
  },
19021
- ...buckets.includes("consentState") ? { consent: { categories: snapshot.consent.categories, apps: snapshot.consent.apps } } : {},
19104
+ ...buckets.includes("consentState") ? { consent: { enabled: context.consentEnforced, categories: snapshot.consent.categories, apps: snapshot.consent.apps } } : {},
19022
19105
  ...geoAllowed && currentGeo !== void 0 ? { geo: currentGeo } : {},
19023
19106
  // Not gated on a capabilities.data bucket: an app only ever sees what it captured or wrote.
19024
19107
  ...attribution === void 0 ? {} : { attribution },
@@ -19343,7 +19426,28 @@ var contextWriteBody = external_exports.object({
19343
19426
  userId: external_exports.string().min(1).max(64),
19344
19427
  writes: external_exports.array(contextWriteSchema).min(1).max(MAX_CONTEXT_WRITES_PER_INSTALL)
19345
19428
  }).strict();
19346
- var brokerBody = external_exports.discriminatedUnion("kind", [pushBody, rpcBody, installsBody, activeBody, contextReadBody, contextWriteBody]);
19429
+ var factsQuery = external_exports.object({
19430
+ kinds: external_exports.array(external_exports.enum(APP_FACT_KINDS)).min(1).max(APP_FACT_KINDS.length).optional(),
19431
+ observedAtGte: external_exports.number().int().nonnegative().safe().optional(),
19432
+ observedAtLt: external_exports.number().int().nonnegative().safe().optional(),
19433
+ limit: external_exports.number().int().min(1).max(MAX_APP_FACTS_PER_PAGE).optional()
19434
+ }).strict().refine((query) => query.observedAtGte === void 0 || query.observedAtLt === void 0 || query.observedAtGte < query.observedAtLt);
19435
+ var factsReadBody = external_exports.object({
19436
+ ...identityFields,
19437
+ kind: external_exports.literal("factsRead"),
19438
+ userId: external_exports.string().min(1).max(64),
19439
+ query: factsQuery.optional(),
19440
+ cursor: external_exports.string().min(1).max(4096).optional()
19441
+ }).strict().refine((body) => body.query === void 0 !== (body.cursor === void 0));
19442
+ var brokerBody = external_exports.discriminatedUnion("kind", [
19443
+ pushBody,
19444
+ rpcBody,
19445
+ installsBody,
19446
+ activeBody,
19447
+ contextReadBody,
19448
+ contextWriteBody,
19449
+ factsReadBody
19450
+ ]);
19347
19451
  var BODY_ENVELOPE_ALLOWANCE_BYTES = 2 * 1024;
19348
19452
  var MAX_BODY_BYTES = MAX_RPC_BYTES + BODY_ENVELOPE_ALLOWANCE_BYTES;
19349
19453
  var parseJson = /* @__PURE__ */ __name((raw2) => {
@@ -19358,12 +19462,62 @@ var constantTimeEqual = /* @__PURE__ */ __name((expected, presented) => {
19358
19462
  const presentedBytes = new TextEncoder().encode(presented);
19359
19463
  return expectedBytes.length === presentedBytes.length && timingSafeEqual(expectedBytes, presentedBytes);
19360
19464
  }, "constantTimeEqual");
19465
+ var factsCursor = external_exports.object({
19466
+ userId: external_exports.string().min(1).max(64),
19467
+ kinds: external_exports.array(external_exports.enum(APP_FACT_KINDS)).min(1).max(APP_FACT_KINDS.length),
19468
+ observedAtGte: external_exports.number().int().nonnegative().safe().nullable(),
19469
+ observedAtLt: external_exports.number().int().nonnegative().safe().nullable(),
19470
+ limit: external_exports.number().int().min(1).max(MAX_APP_FACTS_PER_PAGE),
19471
+ afterRowId: external_exports.number().int().nonnegative().safe(),
19472
+ maxRowId: external_exports.number().int().positive().safe().nullable()
19473
+ }).strict();
19474
+ var cursorKey = /* @__PURE__ */ __name(async (hex3) => {
19475
+ const bytes = Uint8Array.from(hex3.matchAll(/.{2}/g), ([pair]) => Number.parseInt(pair, 16));
19476
+ return crypto.subtle.importKey("raw", bytes, "AES-GCM", false, ["encrypt", "decrypt"]);
19477
+ }, "cursorKey");
19478
+ var encodeBase64Url = /* @__PURE__ */ __name((bytes) => {
19479
+ let binary = "";
19480
+ for (const byte of bytes) {
19481
+ binary += String.fromCharCode(byte);
19482
+ }
19483
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
19484
+ }, "encodeBase64Url");
19485
+ var decodeBase64Url = /* @__PURE__ */ __name((value) => {
19486
+ const base643 = value.replaceAll("-", "+").replaceAll("_", "/");
19487
+ const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
19488
+ const binary = atob(padded);
19489
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
19490
+ }, "decodeBase64Url");
19491
+ var encryptFactsCursor = /* @__PURE__ */ __name(async (key, cursor) => {
19492
+ const iv = crypto.getRandomValues(new Uint8Array(12));
19493
+ const plaintext = new TextEncoder().encode(JSON.stringify(cursor));
19494
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, await cursorKey(key), plaintext));
19495
+ const packed = new Uint8Array(iv.byteLength + ciphertext.byteLength);
19496
+ packed.set(iv);
19497
+ packed.set(ciphertext, iv.byteLength);
19498
+ return encodeBase64Url(packed);
19499
+ }, "encryptFactsCursor");
19500
+ var decryptFactsCursor = /* @__PURE__ */ __name(async (key, encoded) => {
19501
+ try {
19502
+ const packed = decodeBase64Url(encoded);
19503
+ if (packed.byteLength <= 12) {
19504
+ return null;
19505
+ }
19506
+ const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: packed.slice(0, 12) }, await cursorKey(key), packed.slice(12));
19507
+ return JSON.parse(new TextDecoder().decode(plaintext));
19508
+ } catch {
19509
+ return null;
19510
+ }
19511
+ }, "decryptFactsCursor");
19361
19512
  var invalidBody = /* @__PURE__ */ __name(() => {
19362
19513
  return Response.json({ error: "invalid_body" }, { status: 400 });
19363
19514
  }, "invalidBody");
19364
19515
  var forbidden = /* @__PURE__ */ __name(() => {
19365
19516
  return Response.json({ error: "forbidden" }, { status: 403 });
19366
19517
  }, "forbidden");
19518
+ var factsPermissionDenied = /* @__PURE__ */ __name(() => {
19519
+ return Response.json({ error: "facts_permission_denied" }, { status: 403 });
19520
+ }, "factsPermissionDenied");
19367
19521
  var handlePush = /* @__PURE__ */ __name(async (env, body) => {
19368
19522
  if (new TextEncoder().encode(JSON.stringify(body.data ?? null)).length > MAX_PUSH_BYTES) {
19369
19523
  return invalidBody();
@@ -19544,6 +19698,49 @@ var handleContextWrite = /* @__PURE__ */ __name(async (env, body) => {
19544
19698
  const stored = await anonStub(env, body.userId).appContext({ slug: body.slug, writes: body.writes }, currentTraceContext());
19545
19699
  return Response.json({ stored }, { status: 202 });
19546
19700
  }, "handleContextWrite");
19701
+ var initialFactsCursor = /* @__PURE__ */ __name((body) => {
19702
+ const query = body.query;
19703
+ return {
19704
+ userId: body.userId,
19705
+ kinds: query.kinds ?? [...APP_FACT_KINDS],
19706
+ observedAtGte: query.observedAtGte ?? null,
19707
+ observedAtLt: query.observedAtLt ?? null,
19708
+ limit: query.limit ?? MAX_APP_FACTS_PER_PAGE,
19709
+ afterRowId: 0,
19710
+ maxRowId: null
19711
+ };
19712
+ }, "initialFactsCursor");
19713
+ var handleFactsRead = /* @__PURE__ */ __name(async (env, body) => {
19714
+ const app2 = siteRegistry().registry.apps[body.slug];
19715
+ if (app2 === void 0 || !app2.data.includes("facts")) {
19716
+ return factsPermissionDenied();
19717
+ }
19718
+ if (await rateLimited(env, `${body.slug}::facts`)) {
19719
+ return Response.json({ error: "rate_limited" }, { status: 429 });
19720
+ }
19721
+ const decoded = body.cursor === void 0 ? initialFactsCursor(body) : await decryptFactsCursor(body.key, body.cursor);
19722
+ if (decoded === null || decoded.userId !== body.userId || body.cursor !== void 0 && decoded.maxRowId === null) {
19723
+ return Response.json({ error: "invalid_cursor" }, { status: 400 });
19724
+ }
19725
+ const query = {
19726
+ kinds: decoded.kinds,
19727
+ observedAtGte: decoded.observedAtGte,
19728
+ observedAtLt: decoded.observedAtLt,
19729
+ limit: decoded.limit,
19730
+ afterRowId: decoded.afterRowId,
19731
+ maxRowId: decoded.maxRowId
19732
+ };
19733
+ const page = await anonStub(env, body.userId).getAppFacts(body.slug, query, currentTraceContext());
19734
+ if (page === null) {
19735
+ return factsPermissionDenied();
19736
+ }
19737
+ const nextCursor = page.next === null ? null : await encryptFactsCursor(body.key, {
19738
+ ...decoded,
19739
+ afterRowId: page.next.afterRowId,
19740
+ maxRowId: page.next.maxRowId
19741
+ });
19742
+ return Response.json({ items: page.items, nextCursor });
19743
+ }, "handleFactsRead");
19547
19744
  var handleActive = /* @__PURE__ */ __name(async (env, body) => {
19548
19745
  const app2 = siteRegistry().registry.apps[body.slug];
19549
19746
  if (app2 === void 0) {
@@ -19562,8 +19759,14 @@ var handleBroker = /* @__PURE__ */ __name(async (request, env) => {
19562
19759
  if (bytes === null) {
19563
19760
  return Response.json({ error: "too_large" }, { status: 413 });
19564
19761
  }
19565
- const parsed = brokerBody.safeParse(parseJson(new TextDecoder().decode(bytes)));
19762
+ const candidate = parseJson(new TextDecoder().decode(bytes));
19763
+ const parsed = brokerBody.safeParse(candidate);
19566
19764
  if (!parsed.success) {
19765
+ if (typeof candidate === "object" && candidate !== null && "kind" in candidate && candidate.kind === "factsRead") {
19766
+ const malformedFacts = candidate;
19767
+ const error51 = malformedFacts.cursor !== void 0 && malformedFacts.query === void 0 ? "invalid_cursor" : "invalid_query";
19768
+ return Response.json({ error: error51 }, { status: 400 });
19769
+ }
19567
19770
  return invalidBody();
19568
19771
  }
19569
19772
  const body = parsed.data;
@@ -19597,6 +19800,9 @@ var handleBroker = /* @__PURE__ */ __name(async (request, env) => {
19597
19800
  case "contextWrite": {
19598
19801
  return handleContextWrite(env, body);
19599
19802
  }
19803
+ case "factsRead": {
19804
+ return handleFactsRead(env, body);
19805
+ }
19600
19806
  }
19601
19807
  }, "handleBroker");
19602
19808
  var brokerRoutes = new Hono2();
@@ -22846,7 +23052,7 @@ var serverActionContextField = external_exports.object({
22846
23052
  userAgent: external_exports.string().min(1).max(512).optional(),
22847
23053
  locale: external_exports.string().min(1).max(64).optional()
22848
23054
  }).strict().optional(),
22849
- session: external_exports.object({ id: external_exports.string().min(1).max(64), isNew: external_exports.boolean() }).strict().optional(),
23055
+ session: external_exports.object({ id: external_exports.string().min(1).max(64), isNew: external_exports.boolean(), startedAt: external_exports.number().int().nonnegative().safe() }).strict().optional(),
22850
23056
  offline: external_exports.boolean().optional(),
22851
23057
  replay: external_exports.boolean().optional()
22852
23058
  }).strict().optional();
@@ -23559,14 +23765,14 @@ var open = /* @__PURE__ */ __name(async (c) => {
23559
23765
 
23560
23766
  // browser-artifact/meta.json
23561
23767
  var meta_default = {
23562
- version: "0.1.0",
23563
- gitSha: "3aabe60a32914ac6facb6f28b3d21218918de80b",
23564
- builtAt: "2026-08-24T16:10:36.785Z",
23565
- hash: "004a590df1020949be545411bfdd8e25d38d172ea9238d22587658ee798b73c7"
23768
+ version: "0.1.1",
23769
+ gitSha: "45acc2f65889b33f7cf2828b967a26fd879455f0",
23770
+ builtAt: "2026-08-25T22:08:34.269Z",
23771
+ hash: "8f1c955d16978159926d9c98b73ee2d0a3c3d1ea51d4ec8e1b017c3ea6892ea1"
23566
23772
  };
23567
23773
 
23568
23774
  // src/paths/q-js.ts
23569
- import qScript from "./9301296b51353552dafe33a97c95e9755e6108db-q.js.txt";
23775
+ import qScript from "./9dcfd236748459af038da772477100c4bb0223b7-q.js.txt";
23570
23776
 
23571
23777
  // src/apps-q.ts
23572
23778
  import appsQScript from "./apps-q.json";
@@ -25208,7 +25414,7 @@ var MAX_BROWSER_RESULTS_BYTES = 32 * 1024;
25208
25414
  var browserContextFrame = external_exports.object({
25209
25415
  occurredAt: external_exports.number().int().nonnegative().safe(),
25210
25416
  page: external_exports.object({ url: external_exports.string().min(1).max(4096), referrer: external_exports.string().min(1).max(4096).optional() }).strict(),
25211
- session: external_exports.object({ id: external_exports.string().min(1).max(64), isNew: external_exports.boolean() }).strict()
25417
+ session: external_exports.object({ id: external_exports.string().min(1).max(64), isNew: external_exports.boolean(), startedAt: external_exports.number().int().nonnegative().safe() }).strict()
25212
25418
  }).strict();
25213
25419
  var browserResult = external_exports.unknown().refine((value) => {
25214
25420
  return new TextEncoder().encode(JSON.stringify(value)).length <= MAX_BROWSER_RESULT_BYTES;
@@ -25661,6 +25867,20 @@ var AnonDO = class extends DurableObject2 {
25661
25867
  });
25662
25868
  });
25663
25869
  }
25870
+ getAppFacts(slug, query, trace) {
25871
+ return runInvocation({ name: "do.anon.get_app_facts", trace, attrs: { "app.slug": slug } }, () => {
25872
+ return this.enqueue(async () => {
25873
+ const app2 = siteRegistry().registry.apps[slug];
25874
+ if (await this.discardIfUnused() || app2 === void 0 || !app2.data.includes("facts")) {
25875
+ return null;
25876
+ }
25877
+ if (!consentAllows(consentState2(this.kv), slug, app2.consent.category, consentEnforced(this.env))) {
25878
+ return null;
25879
+ }
25880
+ return listAppFacts(this.sql, query);
25881
+ });
25882
+ });
25883
+ }
25664
25884
  // A workflow runs outside request routing, so it re-asks this on every replay rather than trusting
25665
25885
  // the consent its worker's bindings carried when the instance started.
25666
25886
  appAllowed(slug, trace) {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "main": {
3
3
  "version": "0.1.0",
4
- "gitSha": "831251f361f57a3792c7b65f1c6a3689b0e8519e",
5
- "builtAt": "2026-08-25T18:19:08.518Z",
4
+ "gitSha": "45acc2f65889b33f7cf2828b967a26fd879455f0",
5
+ "builtAt": "2026-08-25T22:20:08.908Z",
6
6
  "compatibilityDate": "2026-06-23",
7
7
  "compatibilityFlags": [
8
8
  "nodejs_compat"
@@ -10,8 +10,8 @@
10
10
  "mainModule": "index.js",
11
11
  "modules": [
12
12
  {
13
- "name": "9301296b51353552dafe33a97c95e9755e6108db-q.js.txt",
14
- "path": "main/9301296b51353552dafe33a97c95e9755e6108db-q.js.txt",
13
+ "name": "9dcfd236748459af038da772477100c4bb0223b7-q.js.txt",
14
+ "path": "main/9dcfd236748459af038da772477100c4bb0223b7-q.js.txt",
15
15
  "contentType": "text/plain"
16
16
  },
17
17
  {
@@ -40,8 +40,8 @@
40
40
  },
41
41
  "app-runtime": {
42
42
  "version": "0.1.0",
43
- "gitSha": "831251f361f57a3792c7b65f1c6a3689b0e8519e",
44
- "builtAt": "2026-08-25T18:07:48.888Z",
43
+ "gitSha": "45acc2f65889b33f7cf2828b967a26fd879455f0",
44
+ "builtAt": "2026-08-25T22:08:45.522Z",
45
45
  "compatibilityDate": "2026-06-23",
46
46
  "compatibilityFlags": [
47
47
  "nodejs_compat"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotout/qinto-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Qinto CLI: authenticate against the Qinto platform and operate it from the terminal or from an agent.",
6
6
  "repository": {