@blotout/qinto-cli 0.1.22 → 0.1.23
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 +31 -11
- package/dist/index.js +4662 -4302
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/app-runtime/index.js +200 -89
- package/dist/worker-artifact/main/944c722e73fe144b1067da970f87716a835c697e-q.js.txt +1 -0
- package/dist/worker-artifact/main/index.js +413 -56
- package/dist/worker-artifact/version.json +12 -11
- package/dist/worker-artifact/wfp/index.js +1 -1
- package/package.json +1 -1
- package/dist/worker-artifact/main/7bc13565a6fa9d520d0ebed788d11591e8db5b44-q.js.txt +0 -1
|
@@ -21663,6 +21663,7 @@ var MAX_TOOL_DATA_NODES = 5e3;
|
|
|
21663
21663
|
var CONTROL_DEADLINES_MS = {
|
|
21664
21664
|
noop: { platform: 15e3, site: 1e4 },
|
|
21665
21665
|
lifecycle: { platform: 15e3, site: 1e4 },
|
|
21666
|
+
deleteRequest: { platform: 15e3, site: 1e4 },
|
|
21666
21667
|
migration: { platform: 15e3, site: 1e4 },
|
|
21667
21668
|
schedule: { platform: 65e3, site: 6e4 },
|
|
21668
21669
|
tool: { platform: 55e3, site: 5e4 }
|
|
@@ -21704,6 +21705,14 @@ var lifecycleEventSchema = external_exports.discriminatedUnion("type", [
|
|
|
21704
21705
|
}).strict(),
|
|
21705
21706
|
external_exports.object({ ...lifecycleBase, type: external_exports.literal("uninstalled"), scope: external_exports.enum(["app", "install"]) }).strict()
|
|
21706
21707
|
]);
|
|
21708
|
+
var deleteRequestSchema = external_exports.object({
|
|
21709
|
+
eventId: external_exports.string().min(1).max(64),
|
|
21710
|
+
occurredAt: external_exports.number().int().nonnegative().safe(),
|
|
21711
|
+
install: installSchema2,
|
|
21712
|
+
personId: external_exports.string().min(1).nullable(),
|
|
21713
|
+
anonIds: external_exports.array(external_exports.string().min(1)),
|
|
21714
|
+
identifiers: external_exports.array(external_exports.object({ type: external_exports.enum(["email", "phone", "custom"]), value: external_exports.string().min(1) }).strict()).optional()
|
|
21715
|
+
}).strict();
|
|
21707
21716
|
var migrationSchema = external_exports.discriminatedUnion("phase", [
|
|
21708
21717
|
external_exports.object({
|
|
21709
21718
|
resource: external_exports.string().min(1).max(64),
|
|
@@ -21766,10 +21775,11 @@ var toolSchema2 = external_exports.object({
|
|
|
21766
21775
|
}, "Tool arguments exceed the size cap");
|
|
21767
21776
|
var controlEnvelopeSchema = external_exports.object({
|
|
21768
21777
|
v: external_exports.literal(CONTROL_ENVELOPE_VERSION),
|
|
21769
|
-
kind: external_exports.enum(["noop", "lifecycle", "migration", "schedule", "tool"]),
|
|
21778
|
+
kind: external_exports.enum(["noop", "lifecycle", "deleteRequest", "migration", "schedule", "tool"]),
|
|
21770
21779
|
app: external_exports.object({ slug: external_exports.string().min(1).max(30), version: external_exports.string().min(1).max(32) }).strict(),
|
|
21771
21780
|
install: external_exports.object({ id: external_exports.string().min(1).max(64), ord: external_exports.number().int().min(1), label: external_exports.string().max(100) }).strict().optional(),
|
|
21772
21781
|
lifecycle: lifecycleEventSchema.optional(),
|
|
21782
|
+
deleteRequest: deleteRequestSchema.optional(),
|
|
21773
21783
|
migration: migrationSchema.optional(),
|
|
21774
21784
|
schedule: scheduleSchema2.optional(),
|
|
21775
21785
|
tool: toolSchema2.optional()
|
|
@@ -21777,6 +21787,9 @@ var controlEnvelopeSchema = external_exports.object({
|
|
|
21777
21787
|
if (envelope.kind === "lifecycle" !== (envelope.lifecycle !== void 0)) {
|
|
21778
21788
|
ctx.addIssue({ code: "custom", path: ["lifecycle"], message: "Lifecycle payload must match the control kind" });
|
|
21779
21789
|
}
|
|
21790
|
+
if (envelope.kind === "deleteRequest" !== (envelope.deleteRequest !== void 0)) {
|
|
21791
|
+
ctx.addIssue({ code: "custom", path: ["deleteRequest"], message: "Delete request payload must match the control kind" });
|
|
21792
|
+
}
|
|
21780
21793
|
if (envelope.kind === "migration" !== (envelope.migration !== void 0)) {
|
|
21781
21794
|
ctx.addIssue({ code: "custom", path: ["migration"], message: "Migration payload must match the control kind" });
|
|
21782
21795
|
}
|
|
@@ -21786,8 +21799,8 @@ var controlEnvelopeSchema = external_exports.object({
|
|
|
21786
21799
|
if (envelope.kind === "tool" !== (envelope.tool !== void 0)) {
|
|
21787
21800
|
ctx.addIssue({ code: "custom", path: ["tool"], message: "Tool payload must match the control kind" });
|
|
21788
21801
|
}
|
|
21789
|
-
if (envelope.kind === "lifecycle" && envelope.install === void 0) {
|
|
21790
|
-
ctx.addIssue({ code: "custom", path: ["install"], message:
|
|
21802
|
+
if ((envelope.kind === "lifecycle" || envelope.kind === "deleteRequest") && envelope.install === void 0) {
|
|
21803
|
+
ctx.addIssue({ code: "custom", path: ["install"], message: `${envelope.kind} control needs an install` });
|
|
21791
21804
|
}
|
|
21792
21805
|
if (envelope.kind === "tool" && envelope.install === void 0) {
|
|
21793
21806
|
ctx.addIssue({ code: "custom", path: ["install"], message: "Tool control needs an install" });
|
|
@@ -21826,6 +21839,8 @@ var toolResultSchema = external_exports.object({
|
|
|
21826
21839
|
var controlResponseSchema = external_exports.object({
|
|
21827
21840
|
v: external_exports.literal(CONTROL_ENVELOPE_VERSION),
|
|
21828
21841
|
ok: external_exports.boolean(),
|
|
21842
|
+
// The bundle has no delete request handler, so a retry cannot succeed.
|
|
21843
|
+
skipped: external_exports.literal(true).optional(),
|
|
21829
21844
|
tool: toolResultSchema.optional(),
|
|
21830
21845
|
migration: external_exports.union([
|
|
21831
21846
|
external_exports.object({ done: external_exports.literal(true) }).strict(),
|
|
@@ -26323,6 +26338,16 @@ var identifierField2 = external_exports.string().trim().min(1).refine((value) =>
|
|
|
26323
26338
|
description: "Who the request applies to: a canonical Qinto id (`anon_\u2026`, or a `tag_user_id` adopted from EdgeTag), or any identifier from your own systems (email, phone, custom id). Internal `gid_\u2026` ids are rejected.",
|
|
26324
26339
|
example: "crm-user-8412"
|
|
26325
26340
|
});
|
|
26341
|
+
var readIdentifierField = identifierField2.optional().openapi({
|
|
26342
|
+
param: { name: "identifier", in: "query" },
|
|
26343
|
+
description: "User to read: any identifier from your own systems (email, phone, custom id), or a canonical Qinto id (`anon_\u2026`, or a `tag_user_id` adopted from EdgeTag). Omit it to read the user from the first-party cookie instead. Internal `gid_\u2026` ids are rejected.",
|
|
26344
|
+
example: "ada@example.com"
|
|
26345
|
+
});
|
|
26346
|
+
var canonicalIdentifierField = external_exports.string().min(1).optional().openapi({
|
|
26347
|
+
param: { name: "identifier", in: "query" },
|
|
26348
|
+
description: "Canonical Qinto id (`anon_\u2026`) of the user to read. Omit it to resolve the user from the first-party cookie instead. Reading by a custom identifier arrives with authenticated API access.",
|
|
26349
|
+
example: "anon_7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"
|
|
26350
|
+
});
|
|
26326
26351
|
var consentCategoriesField = external_exports.object({
|
|
26327
26352
|
// Necessary consent cannot be opted out.
|
|
26328
26353
|
necessary: external_exports.literal(true).optional().openapi({
|
|
@@ -27150,6 +27175,9 @@ var linkedAnonsPage = /* @__PURE__ */ __name((sql, afterRowId, limit) => {
|
|
|
27150
27175
|
var linkedAnonsExcept = /* @__PURE__ */ __name((sql, originAnonId) => {
|
|
27151
27176
|
return sql.exec("SELECT key FROM facts WHERE kind = 'anon' AND key != ?", originAnonId).toArray().map((row) => row.key);
|
|
27152
27177
|
}, "linkedAnonsExcept");
|
|
27178
|
+
var allLinkedAnons = /* @__PURE__ */ __name((sql) => {
|
|
27179
|
+
return sql.exec("SELECT key FROM facts WHERE kind = 'anon' ORDER BY rowid").toArray().map((row) => row.key);
|
|
27180
|
+
}, "allLinkedAnons");
|
|
27153
27181
|
|
|
27154
27182
|
// src/id-graph/person.ts
|
|
27155
27183
|
var IDENTITY_CAPABILITY = "identity";
|
|
@@ -27227,6 +27255,124 @@ var identityFields = {
|
|
|
27227
27255
|
key: external_exports.string().min(1)
|
|
27228
27256
|
};
|
|
27229
27257
|
|
|
27258
|
+
// src/apps/currency-rates.ts
|
|
27259
|
+
var CURRENCY_FEED_URL = "https://cdn.shopify.com/s/javascripts/currencies.js";
|
|
27260
|
+
var RATES_TTL_MS = 60 * 60 * 1e3;
|
|
27261
|
+
var RETRY_AFTER_FAILURE_MS = 60 * 1e3;
|
|
27262
|
+
var FEED_TIMEOUT_MS = 5e3;
|
|
27263
|
+
var FEED_EDGE_CACHE_TTL_S = 8 * 60 * 60;
|
|
27264
|
+
var MIN_CURRENCY_CODES = 100;
|
|
27265
|
+
var currencyMemo;
|
|
27266
|
+
var parseRatesLiteral = /* @__PURE__ */ __name((feed) => {
|
|
27267
|
+
const opening = "rates:{";
|
|
27268
|
+
const start = feed.indexOf(opening);
|
|
27269
|
+
if (start === -1) {
|
|
27270
|
+
return null;
|
|
27271
|
+
}
|
|
27272
|
+
const entry = /([A-Z]{3}):(-?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)([,}])/y;
|
|
27273
|
+
entry.lastIndex = start + opening.length;
|
|
27274
|
+
const rates = {};
|
|
27275
|
+
for (; ; ) {
|
|
27276
|
+
const match2 = entry.exec(feed);
|
|
27277
|
+
if (match2 === null) {
|
|
27278
|
+
return null;
|
|
27279
|
+
}
|
|
27280
|
+
const [, code, value, terminator] = match2;
|
|
27281
|
+
if (Object.hasOwn(rates, code)) {
|
|
27282
|
+
return null;
|
|
27283
|
+
}
|
|
27284
|
+
rates[code] = Number(value);
|
|
27285
|
+
if (terminator === "}") {
|
|
27286
|
+
return rates;
|
|
27287
|
+
}
|
|
27288
|
+
}
|
|
27289
|
+
}, "parseRatesLiteral");
|
|
27290
|
+
var parseCurrencyFeed = /* @__PURE__ */ __name((feed) => {
|
|
27291
|
+
const rates = parseRatesLiteral(feed);
|
|
27292
|
+
if (rates === null) {
|
|
27293
|
+
return { ok: false, reason: "the rates literal does not parse" };
|
|
27294
|
+
}
|
|
27295
|
+
if (rates["USD"] !== 1) {
|
|
27296
|
+
return { ok: false, reason: "USD is not 1" };
|
|
27297
|
+
}
|
|
27298
|
+
const invalid = Object.entries(rates).find(([, rate]) => !Number.isFinite(rate) || rate <= 0);
|
|
27299
|
+
if (invalid !== void 0) {
|
|
27300
|
+
return { ok: false, reason: `${invalid[0]} is not a positive finite rate` };
|
|
27301
|
+
}
|
|
27302
|
+
const count = Object.keys(rates).length;
|
|
27303
|
+
if (count < MIN_CURRENCY_CODES) {
|
|
27304
|
+
return { ok: false, reason: `the feed has ${count} codes` };
|
|
27305
|
+
}
|
|
27306
|
+
return { ok: true, rates };
|
|
27307
|
+
}, "parseCurrencyFeed");
|
|
27308
|
+
var fetchCurrencyRates = /* @__PURE__ */ __name(async () => {
|
|
27309
|
+
return traced("currency.fetch", { attrs: { "http.url": CURRENCY_FEED_URL } }, async () => {
|
|
27310
|
+
let feed;
|
|
27311
|
+
try {
|
|
27312
|
+
const response = await fetch(CURRENCY_FEED_URL, {
|
|
27313
|
+
signal: AbortSignal.timeout(FEED_TIMEOUT_MS),
|
|
27314
|
+
cf: { cacheTtlByStatus: { "200-299": FEED_EDGE_CACHE_TTL_S, "300-599": 0 } }
|
|
27315
|
+
});
|
|
27316
|
+
if (!response.ok) {
|
|
27317
|
+
addSpanEvent("currency fetch failed", { level: "error", attrs: { status: response.status } });
|
|
27318
|
+
return null;
|
|
27319
|
+
}
|
|
27320
|
+
feed = await response.text();
|
|
27321
|
+
} catch (error61) {
|
|
27322
|
+
addSpanEvent("currency fetch failed", { level: "error", attrs: { error: String(error61) } });
|
|
27323
|
+
return null;
|
|
27324
|
+
}
|
|
27325
|
+
const verdict = parseCurrencyFeed(feed);
|
|
27326
|
+
if (!verdict.ok) {
|
|
27327
|
+
addSpanEvent("currency feed rejected", { level: "error", attrs: { reason: verdict.reason } });
|
|
27328
|
+
return null;
|
|
27329
|
+
}
|
|
27330
|
+
return verdict.rates;
|
|
27331
|
+
});
|
|
27332
|
+
}, "fetchCurrencyRates");
|
|
27333
|
+
var refreshCurrencyRates = /* @__PURE__ */ __name(async () => {
|
|
27334
|
+
const rates = await fetchCurrencyRates();
|
|
27335
|
+
const now = Date.now();
|
|
27336
|
+
if (rates === null) {
|
|
27337
|
+
const current2 = currencyMemo?.current ?? null;
|
|
27338
|
+
currencyMemo = { current: current2, nextAttemptAt: now + RETRY_AFTER_FAILURE_MS };
|
|
27339
|
+
return current2;
|
|
27340
|
+
}
|
|
27341
|
+
const current = { rates, fetchedAt: now };
|
|
27342
|
+
currencyMemo = { current, nextAttemptAt: now + RATES_TTL_MS };
|
|
27343
|
+
return current;
|
|
27344
|
+
}, "refreshCurrencyRates");
|
|
27345
|
+
var currentCurrencyRates = /* @__PURE__ */ __name(async (ctx) => {
|
|
27346
|
+
const now = Date.now();
|
|
27347
|
+
if (currencyMemo !== void 0 && now < currencyMemo.nextAttemptAt) {
|
|
27348
|
+
return currencyMemo.current;
|
|
27349
|
+
}
|
|
27350
|
+
const stale = currencyMemo?.current ?? null;
|
|
27351
|
+
if (stale === null) {
|
|
27352
|
+
return refreshCurrencyRates();
|
|
27353
|
+
}
|
|
27354
|
+
currencyMemo = { current: stale, nextAttemptAt: now + RETRY_AFTER_FAILURE_MS };
|
|
27355
|
+
ctx.waitUntil(
|
|
27356
|
+
runInvocation({ name: "currency.refresh", trace: currentTraceContext() }, () => {
|
|
27357
|
+
return refreshCurrencyRates();
|
|
27358
|
+
})
|
|
27359
|
+
);
|
|
27360
|
+
return stale;
|
|
27361
|
+
}, "currentCurrencyRates");
|
|
27362
|
+
|
|
27363
|
+
// src/apps/broker-currency.ts
|
|
27364
|
+
var currencyRatesBody = external_exports.object({
|
|
27365
|
+
...identityFields,
|
|
27366
|
+
kind: external_exports.literal("currencyRates")
|
|
27367
|
+
}).strict();
|
|
27368
|
+
var handleCurrencyRates = /* @__PURE__ */ __name(async (ctx) => {
|
|
27369
|
+
const current = await currentCurrencyRates(ctx);
|
|
27370
|
+
if (current === null) {
|
|
27371
|
+
return Response.json({ error: "currency_rates_unavailable" }, { status: 503 });
|
|
27372
|
+
}
|
|
27373
|
+
return Response.json(current);
|
|
27374
|
+
}, "handleCurrencyRates");
|
|
27375
|
+
|
|
27230
27376
|
// src/apps/emit-payload.ts
|
|
27231
27377
|
var emitPayloadSchema = external_exports.object({
|
|
27232
27378
|
event: external_exports.string().min(1),
|
|
@@ -28029,6 +28175,7 @@ var brokerBody = external_exports.discriminatedUnion("kind", [
|
|
|
28029
28175
|
contextWriteBody,
|
|
28030
28176
|
factsReadBody,
|
|
28031
28177
|
identityReadBody,
|
|
28178
|
+
currencyRatesBody,
|
|
28032
28179
|
trackBody
|
|
28033
28180
|
]);
|
|
28034
28181
|
var BODY_ENVELOPE_ALLOWANCE_BYTES = 2 * 1024;
|
|
@@ -28364,7 +28511,7 @@ var handleActive = /* @__PURE__ */ __name(async (env, body) => {
|
|
|
28364
28511
|
}
|
|
28365
28512
|
return Response.json({ active: true });
|
|
28366
28513
|
}, "handleActive");
|
|
28367
|
-
var handleBroker = /* @__PURE__ */ __name(async (request, env) => {
|
|
28514
|
+
var handleBroker = /* @__PURE__ */ __name(async (request, env, ctx) => {
|
|
28368
28515
|
const bytes = await readBoundedBody(request, MAX_BODY_BYTES);
|
|
28369
28516
|
if (bytes === null) {
|
|
28370
28517
|
return Response.json({ error: "too_large" }, { status: 413 });
|
|
@@ -28416,6 +28563,9 @@ var handleBroker = /* @__PURE__ */ __name(async (request, env) => {
|
|
|
28416
28563
|
case "identityRead": {
|
|
28417
28564
|
return handleIdentityRead(env, body);
|
|
28418
28565
|
}
|
|
28566
|
+
case "currencyRates": {
|
|
28567
|
+
return handleCurrencyRates(ctx);
|
|
28568
|
+
}
|
|
28419
28569
|
case "track": {
|
|
28420
28570
|
return handleTrack(env, body);
|
|
28421
28571
|
}
|
|
@@ -28426,7 +28576,7 @@ var dispatchGated = /* @__PURE__ */ __name((c) => {
|
|
|
28426
28576
|
if (c.env.DEPLOY_TARGET !== "dispatch") {
|
|
28427
28577
|
return c.notFound();
|
|
28428
28578
|
}
|
|
28429
|
-
return handleBroker(c.req.raw, c.env);
|
|
28579
|
+
return handleBroker(c.req.raw, c.env, c.executionCtx);
|
|
28430
28580
|
}, "dispatchGated");
|
|
28431
28581
|
for (const path of BROKER_PATHS) {
|
|
28432
28582
|
brokerRoutes.post(path, dispatchGated);
|
|
@@ -28438,7 +28588,7 @@ var Broker = class extends WorkerEntrypoint {
|
|
|
28438
28588
|
fetch(request) {
|
|
28439
28589
|
const trace = parseTraceContext(request.headers.get(TRACE_HEADER));
|
|
28440
28590
|
return runInvocation({ name: "broker", trace }, () => {
|
|
28441
|
-
return handleBroker(request, this.env);
|
|
28591
|
+
return handleBroker(request, this.env, this.ctx);
|
|
28442
28592
|
});
|
|
28443
28593
|
}
|
|
28444
28594
|
};
|
|
@@ -29439,20 +29589,17 @@ var matchEndpoint = /* @__PURE__ */ __name((app2, path, method) => {
|
|
|
29439
29589
|
if (!isHttpMethod(method)) {
|
|
29440
29590
|
return void 0;
|
|
29441
29591
|
}
|
|
29442
|
-
const serving = app2.endpoints.filter((endpoint) => {
|
|
29443
|
-
return endpoint.methods.includes(method);
|
|
29444
|
-
});
|
|
29445
29592
|
const matched = matchEndpointPath(
|
|
29446
|
-
|
|
29593
|
+
app2.endpoints.map((endpoint) => endpoint.path),
|
|
29447
29594
|
path
|
|
29448
29595
|
);
|
|
29449
29596
|
if (matched === void 0) {
|
|
29450
29597
|
return void 0;
|
|
29451
29598
|
}
|
|
29452
|
-
const declared =
|
|
29599
|
+
const declared = app2.endpoints.find((endpoint) => {
|
|
29453
29600
|
return endpoint.path === matched.route;
|
|
29454
29601
|
});
|
|
29455
|
-
if (!["public", "token", "visitor"].includes(declared.auth) || declared.mode !== "webhook" && declared.mode !== "api") {
|
|
29602
|
+
if (!declared.methods.includes(method) || !["public", "token", "visitor"].includes(declared.auth) || declared.mode !== "webhook" && declared.mode !== "api") {
|
|
29456
29603
|
return void 0;
|
|
29457
29604
|
}
|
|
29458
29605
|
return {
|
|
@@ -30058,7 +30205,7 @@ appUiRoutes.all("/apps/:slug/ui/*", (c) => {
|
|
|
30058
30205
|
var apiInfo = {
|
|
30059
30206
|
title: "Qinto Edge API",
|
|
30060
30207
|
version: "0.1.0",
|
|
30061
|
-
description:
|
|
30208
|
+
description: 'HTTP API for recording user activity on the Qinto platform: track events, attach identity traits, link custom identifiers, and record or read a user\u2019s consent and properties.\n\nEach request applies to one user. Writes address that user by any identifier of your own (email, phone, custom id) or a canonical Qinto id (`anon_\u2026`); the same identifier always reaches the same user. Reads take a canonical id or the first-party cookie; `GET /v1/session` also accepts your own.\n\nEvery `/v1` operation takes a worker access token as `Authorization: Bearer <token>`, scoped to the endpoints it may call; generate one from the Qinto platform\u2019s worker access tokens page. Errors use one JSON envelope: `error` is a machine-readable slug to switch on, and `details` optionally carries field-level validation errors. The health check is unauthenticated and answers `{ "status": "success" }`.'
|
|
30062
30209
|
};
|
|
30063
30210
|
var apiTags = [
|
|
30064
30211
|
{
|
|
@@ -30106,7 +30253,7 @@ var ERRORS = {
|
|
|
30106
30253
|
},
|
|
30107
30254
|
internal: {
|
|
30108
30255
|
status: 500,
|
|
30109
|
-
description: "Unexpected server error. Nothing is guaranteed to have been persisted; reads are safe to retry, and conversions dedupe on their order id, but
|
|
30256
|
+
description: "Unexpected server error. Nothing is guaranteed to have been persisted; reads are safe to retry, and conversions dedupe on their order id, but retrying an ingestion request can deliver the event to the site\u2019s apps again."
|
|
30110
30257
|
}
|
|
30111
30258
|
};
|
|
30112
30259
|
var DETAILS_SLUGS = /* @__PURE__ */ new Set(["invalid_params", "invalid_body"]);
|
|
@@ -30363,6 +30510,140 @@ var health = createApiRouter().openapi(definition, (c) => {
|
|
|
30363
30510
|
return respond(c, healthResponse, { status: "success" });
|
|
30364
30511
|
});
|
|
30365
30512
|
|
|
30513
|
+
// src/id-graph/delete-request.ts
|
|
30514
|
+
var readAlias = /* @__PURE__ */ __name((env, key) => {
|
|
30515
|
+
return traced("rpc alias.get", {}, () => {
|
|
30516
|
+
return aliasStub(env, key).get(currentTraceContext());
|
|
30517
|
+
});
|
|
30518
|
+
}, "readAlias");
|
|
30519
|
+
var readAnon = /* @__PURE__ */ __name((env, anonId) => {
|
|
30520
|
+
return traced("rpc anon.erasable", { attrs: { "anon.id": anonId } }, () => {
|
|
30521
|
+
return anonStub(env, anonId).erasable(currentTraceContext());
|
|
30522
|
+
});
|
|
30523
|
+
}, "readAnon");
|
|
30524
|
+
var readPerson = /* @__PURE__ */ __name((env, globalId) => {
|
|
30525
|
+
return traced("rpc global.erasable", { attrs: { "global.id": globalId } }, () => {
|
|
30526
|
+
return globalStub(env, globalId).erasable(currentTraceContext());
|
|
30527
|
+
});
|
|
30528
|
+
}, "readPerson");
|
|
30529
|
+
var typedOf = /* @__PURE__ */ __name(async (env, value) => {
|
|
30530
|
+
if (isCanonicalId(value)) {
|
|
30531
|
+
return { inputType: "anon", kind: "anon", name: value, alias: null, personId: null, anonId: value };
|
|
30532
|
+
}
|
|
30533
|
+
if (isGlobalId(value)) {
|
|
30534
|
+
return { inputType: "person", kind: "global", name: value, alias: null, personId: value, anonId: null };
|
|
30535
|
+
}
|
|
30536
|
+
const identifier = classifyIdentifier(value);
|
|
30537
|
+
const key = await aliasKey(identifier);
|
|
30538
|
+
const assignment = await readAlias(env, key);
|
|
30539
|
+
return {
|
|
30540
|
+
inputType: identifier.type,
|
|
30541
|
+
kind: "alias",
|
|
30542
|
+
name: key,
|
|
30543
|
+
alias: assignment === null ? null : identifier,
|
|
30544
|
+
personId: assignment?.globalId ?? null,
|
|
30545
|
+
anonId: assignment?.anonId ?? null
|
|
30546
|
+
};
|
|
30547
|
+
}, "typedOf");
|
|
30548
|
+
var uniqueIdentifiers = /* @__PURE__ */ __name((identifiers) => {
|
|
30549
|
+
const byKey = new Map(identifiers.map((identifier) => [`${identifier.type}:${identifier.value}`, identifier]));
|
|
30550
|
+
return [...byKey.values()];
|
|
30551
|
+
}, "uniqueIdentifiers");
|
|
30552
|
+
var reachFrom = /* @__PURE__ */ __name(async (env, typed) => {
|
|
30553
|
+
const anons = /* @__PURE__ */ new Map();
|
|
30554
|
+
let personId = typed.personId;
|
|
30555
|
+
if (personId === null && typed.anonId !== null) {
|
|
30556
|
+
const anon = await readAnon(env, typed.anonId);
|
|
30557
|
+
if (anon !== null) {
|
|
30558
|
+
anons.set(typed.anonId, anon);
|
|
30559
|
+
personId = anon.globalId;
|
|
30560
|
+
}
|
|
30561
|
+
}
|
|
30562
|
+
const person2 = personId === null ? null : await readPerson(env, personId);
|
|
30563
|
+
for (const anonId of person2?.anonIds ?? []) {
|
|
30564
|
+
const anon = anons.has(anonId) ? null : await readAnon(env, anonId);
|
|
30565
|
+
if (anon !== null) {
|
|
30566
|
+
anons.set(anonId, anon);
|
|
30567
|
+
}
|
|
30568
|
+
}
|
|
30569
|
+
return { personId, person: person2, anons };
|
|
30570
|
+
}, "reachFrom");
|
|
30571
|
+
var ownedAliases = /* @__PURE__ */ __name(async (env, typed, reached) => {
|
|
30572
|
+
const aliasKeys = [];
|
|
30573
|
+
const identifiers = [];
|
|
30574
|
+
const held = [...reached.person?.identifiers ?? [], ...[...reached.anons.values()].flatMap((anon) => anon.identifiers)];
|
|
30575
|
+
for (const identifier of uniqueIdentifiers(held)) {
|
|
30576
|
+
const key = await aliasKey(identifier);
|
|
30577
|
+
const assignment = key === typed.name ? null : await readAlias(env, key);
|
|
30578
|
+
const owner = assignment?.globalId ?? null;
|
|
30579
|
+
const owned = assignment === null || (owner === null ? [...reached.anons.keys()].some((anonId) => anonId === assignment.anonId) : owner === reached.personId);
|
|
30580
|
+
if (key !== typed.name && owned) {
|
|
30581
|
+
identifiers.push(identifier);
|
|
30582
|
+
if (assignment !== null) {
|
|
30583
|
+
aliasKeys.push(key);
|
|
30584
|
+
}
|
|
30585
|
+
}
|
|
30586
|
+
}
|
|
30587
|
+
if (typed.alias !== null) {
|
|
30588
|
+
aliasKeys.push(typed.name);
|
|
30589
|
+
identifiers.push(typed.alias);
|
|
30590
|
+
}
|
|
30591
|
+
return { aliasKeys, identifiers };
|
|
30592
|
+
}, "ownedAliases");
|
|
30593
|
+
var planOf = /* @__PURE__ */ __name(async (env, typed) => {
|
|
30594
|
+
const reached = await reachFrom(env, typed);
|
|
30595
|
+
const { aliasKeys, identifiers } = await ownedAliases(env, typed, reached);
|
|
30596
|
+
return {
|
|
30597
|
+
inputType: typed.inputType,
|
|
30598
|
+
personId: reached.person === null ? null : reached.personId,
|
|
30599
|
+
anonIds: [...reached.anons.keys()],
|
|
30600
|
+
aliasKeys,
|
|
30601
|
+
identifiers
|
|
30602
|
+
};
|
|
30603
|
+
}, "planOf");
|
|
30604
|
+
var planDeleteRequest = /* @__PURE__ */ __name(async (env, value) => {
|
|
30605
|
+
return planOf(env, await typedOf(env, value));
|
|
30606
|
+
}, "planDeleteRequest");
|
|
30607
|
+
var ERASERS = Object.freeze({
|
|
30608
|
+
alias: /* @__PURE__ */ __name((env, name) => {
|
|
30609
|
+
return traced("rpc alias.erase", {}, () => {
|
|
30610
|
+
return aliasStub(env, name).erase(currentTraceContext());
|
|
30611
|
+
});
|
|
30612
|
+
}, "alias"),
|
|
30613
|
+
anon: /* @__PURE__ */ __name((env, name) => {
|
|
30614
|
+
return traced("rpc anon.erase", { attrs: { "anon.id": name } }, () => {
|
|
30615
|
+
return anonStub(env, name).erase(currentTraceContext());
|
|
30616
|
+
});
|
|
30617
|
+
}, "anon"),
|
|
30618
|
+
global: /* @__PURE__ */ __name((env, name) => {
|
|
30619
|
+
return traced("rpc global.erase", { attrs: { "global.id": name } }, () => {
|
|
30620
|
+
return globalStub(env, name).erase(currentTraceContext());
|
|
30621
|
+
});
|
|
30622
|
+
}, "global")
|
|
30623
|
+
});
|
|
30624
|
+
var eraseOrder = /* @__PURE__ */ __name((plan, typed) => {
|
|
30625
|
+
const steps = [
|
|
30626
|
+
...plan.aliasKeys.map((name) => ({ kind: "alias", name })),
|
|
30627
|
+
...plan.anonIds.map((name) => ({ kind: "anon", name })),
|
|
30628
|
+
...plan.personId === null ? [] : [{ kind: "global", name: plan.personId }]
|
|
30629
|
+
];
|
|
30630
|
+
const isTyped = /* @__PURE__ */ __name((step) => {
|
|
30631
|
+
return step.kind === typed.kind && step.name === typed.name;
|
|
30632
|
+
}, "isTyped");
|
|
30633
|
+
return [...steps.filter((step) => !isTyped(step)), ...steps.filter(isTyped)];
|
|
30634
|
+
}, "eraseOrder");
|
|
30635
|
+
var runDeleteRequest = /* @__PURE__ */ __name(async (env, value) => {
|
|
30636
|
+
const typed = await typedOf(env, value);
|
|
30637
|
+
const plan = await planOf(env, typed);
|
|
30638
|
+
const erased = { alias: 0, anon: 0, global: 0 };
|
|
30639
|
+
for (const step of eraseOrder(plan, typed)) {
|
|
30640
|
+
if (await ERASERS[step.kind](env, step.name)) {
|
|
30641
|
+
erased[step.kind] += 1;
|
|
30642
|
+
}
|
|
30643
|
+
}
|
|
30644
|
+
return { inputType: plan.inputType, anons: erased.anon, aliases: erased.alias, persons: erased.global };
|
|
30645
|
+
}, "runDeleteRequest");
|
|
30646
|
+
|
|
30366
30647
|
// src/id-graph/inspect.ts
|
|
30367
30648
|
var MAX_TABLE_PAGE = 100;
|
|
30368
30649
|
var INTERNAL_TABLE = /^(sqlite_|_cf_)/;
|
|
@@ -30487,6 +30768,7 @@ var rowsBody = inspectBody.extend({
|
|
|
30487
30768
|
offset: external_exports.number().int().min(0).default(0),
|
|
30488
30769
|
limit: external_exports.number().int().min(1).max(MAX_TABLE_PAGE).default(MAX_TABLE_PAGE)
|
|
30489
30770
|
});
|
|
30771
|
+
var valueBody = external_exports.object({ value: external_exports.string().min(1) });
|
|
30490
30772
|
var readBody = /* @__PURE__ */ __name(async (c, schema) => {
|
|
30491
30773
|
const parsed = schema.safeParse(await c.req.json().catch(() => null));
|
|
30492
30774
|
return parsed.success ? parsed.data : null;
|
|
@@ -30514,6 +30796,20 @@ idGraphInspect.post("/internal/id-graph/rows", async (c) => {
|
|
|
30514
30796
|
}
|
|
30515
30797
|
return c.json({ page: await inspectObjectTable(c.env, body) });
|
|
30516
30798
|
});
|
|
30799
|
+
idGraphInspect.post("/internal/id-graph/plan", async (c) => {
|
|
30800
|
+
const body = await readBody(c, valueBody);
|
|
30801
|
+
if (body === null) {
|
|
30802
|
+
return c.json({ error: "invalid_body" }, 400);
|
|
30803
|
+
}
|
|
30804
|
+
return c.json(await planDeleteRequest(c.env, body.value));
|
|
30805
|
+
});
|
|
30806
|
+
idGraphInspect.post("/internal/id-graph/delete", async (c) => {
|
|
30807
|
+
const body = await readBody(c, valueBody);
|
|
30808
|
+
if (body === null) {
|
|
30809
|
+
return c.json({ error: "invalid_body" }, 400);
|
|
30810
|
+
}
|
|
30811
|
+
return c.json(await runDeleteRequest(c.env, body.value));
|
|
30812
|
+
});
|
|
30517
30813
|
|
|
30518
30814
|
// src/paths/open.ts
|
|
30519
30815
|
var withSetCookie = /* @__PURE__ */ __name((res, cookies) => {
|
|
@@ -30601,14 +30897,14 @@ var open2 = /* @__PURE__ */ __name(async (c) => {
|
|
|
30601
30897
|
|
|
30602
30898
|
// browser-artifact/meta.json
|
|
30603
30899
|
var meta_default = {
|
|
30604
|
-
version: "0.1.
|
|
30605
|
-
gitSha: "
|
|
30606
|
-
builtAt: "2026-09-
|
|
30607
|
-
hash: "
|
|
30900
|
+
version: "0.1.11",
|
|
30901
|
+
gitSha: "bb87bca6d3b96627f24bc0c29675f2f19680ce60",
|
|
30902
|
+
builtAt: "2026-09-28T04:35:01.606Z",
|
|
30903
|
+
hash: "e32dfe041826d6daaa3682d1f5cac137ffcc6a24f55bfef1a936f7e3ef4cde12"
|
|
30608
30904
|
};
|
|
30609
30905
|
|
|
30610
30906
|
// src/paths/q-js.ts
|
|
30611
|
-
import qScript from "./
|
|
30907
|
+
import qScript from "./944c722e73fe144b1067da970f87716a835c697e-q.js.txt";
|
|
30612
30908
|
|
|
30613
30909
|
// src/apps-q.ts
|
|
30614
30910
|
import appsQScript from "./apps-q.json";
|
|
@@ -30854,11 +31150,7 @@ var consent = createApiRouter().openapi(definition4, async (c) => {
|
|
|
30854
31150
|
|
|
30855
31151
|
// src/paths/v1/consent-state.ts
|
|
30856
31152
|
var consentStateQuery = external_exports.object({
|
|
30857
|
-
identifier:
|
|
30858
|
-
param: { name: "identifier", in: "query" },
|
|
30859
|
-
description: "Canonical Qinto id (`anon_\u2026`) of the user to read. Omit it to resolve the user from the first-party cookie instead. Reading by a custom identifier arrives with authenticated API access.",
|
|
30860
|
-
example: "anon_7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"
|
|
30861
|
-
})
|
|
31153
|
+
identifier: canonicalIdentifierField
|
|
30862
31154
|
});
|
|
30863
31155
|
var consentStateResponse = external_exports.object({
|
|
30864
31156
|
categories: external_exports.object({
|
|
@@ -30885,7 +31177,7 @@ var definition5 = createRoute({
|
|
|
30885
31177
|
summary: "Get user consent",
|
|
30886
31178
|
description: operationDescription({
|
|
30887
31179
|
intro: "Returns the consent state currently stored for the user.",
|
|
30888
|
-
howItWorks: "A request that carries neither
|
|
31180
|
+
howItWorks: "A request that carries neither an `identifier` nor the cookie \u2014 or an `identifier` that is not canonical \u2014 fails with `invalid_params`. A choice saved on another session reaches this one separately, so a read taken right after a write elsewhere can return the previous value, and a session with no further activity can stay behind indefinitely. Read back from the session that made the change when you need the value you just wrote."
|
|
30889
31181
|
}),
|
|
30890
31182
|
request: { query: consentStateQuery },
|
|
30891
31183
|
responses: {
|
|
@@ -30956,11 +31248,7 @@ var identify = createApiRouter().openapi(definition6, async (c) => {
|
|
|
30956
31248
|
|
|
30957
31249
|
// src/paths/v1/person.ts
|
|
30958
31250
|
var personQuery = external_exports.object({
|
|
30959
|
-
identifier:
|
|
30960
|
-
param: { name: "identifier", in: "query" },
|
|
30961
|
-
description: "User to read: any identifier from your own systems (email, phone, custom id), or a canonical Qinto id (`anon_\u2026`, or a `tag_user_id` adopted from EdgeTag). Omit it to read the user from the first-party cookie instead. Internal `gid_\u2026` ids are rejected.",
|
|
30962
|
-
example: "ada@example.com"
|
|
30963
|
-
}),
|
|
31251
|
+
identifier: readIdentifierField,
|
|
30964
31252
|
cursor: external_exports.string().regex(/^\d+$/).optional().openapi({
|
|
30965
31253
|
param: { name: "cursor", in: "query" },
|
|
30966
31254
|
description: "The `nextCursor` of the previous page. Omit it for the first page.",
|
|
@@ -31013,11 +31301,7 @@ var person = createApiRouter().openapi(definition7, async (c) => {
|
|
|
31013
31301
|
|
|
31014
31302
|
// src/paths/v1/properties.ts
|
|
31015
31303
|
var propertiesQuery = external_exports.object({
|
|
31016
|
-
identifier:
|
|
31017
|
-
param: { name: "identifier", in: "query" },
|
|
31018
|
-
description: "Canonical Qinto id (`anon_\u2026`) of the user to read. Omit it to resolve the user from the first-party cookie instead. Reading by a custom identifier arrives with authenticated API access.",
|
|
31019
|
-
example: "anon_7b8d1a52-6c1e-4b6f-9a30-2f8a54d1c3e9"
|
|
31020
|
-
})
|
|
31304
|
+
identifier: canonicalIdentifierField
|
|
31021
31305
|
});
|
|
31022
31306
|
var propertiesResponse = external_exports.record(external_exports.string(), external_exports.unknown()).openapi("UserProperties", { description: "Every property currently stored for the user, keyed by property name." });
|
|
31023
31307
|
var definition8 = createRoute({
|
|
@@ -31028,10 +31312,7 @@ var definition8 = createRoute({
|
|
|
31028
31312
|
security: [{ QintoWorkerAccessToken: [] }],
|
|
31029
31313
|
middleware: [requireScope(SCOPE.propertiesRead)],
|
|
31030
31314
|
summary: "Get user properties",
|
|
31031
|
-
description: operationDescription({
|
|
31032
|
-
intro: "Returns every property currently stored for the user.",
|
|
31033
|
-
howItWorks: "A request that carries neither a `identifier` nor the cookie \u2014 or a `identifier` that is not canonical \u2014 fails with `invalid_params`."
|
|
31034
|
-
}),
|
|
31315
|
+
description: operationDescription({ intro: "Returns every property currently stored for the user." }),
|
|
31035
31316
|
request: { query: propertiesQuery },
|
|
31036
31317
|
responses: {
|
|
31037
31318
|
200: {
|
|
@@ -31054,11 +31335,7 @@ var properties = createApiRouter().openapi(definition8, async (c) => {
|
|
|
31054
31335
|
|
|
31055
31336
|
// src/paths/v1/session.ts
|
|
31056
31337
|
var sessionQuery = external_exports.object({
|
|
31057
|
-
identifier:
|
|
31058
|
-
param: { name: "identifier", in: "query" },
|
|
31059
|
-
description: "User to read: any identifier from your own systems (email, phone, custom id), or a canonical Qinto id (`anon_\u2026`). Omit it to read the user from the first-party cookie instead. Internal `gid_\u2026` ids are rejected.",
|
|
31060
|
-
example: "ada@example.com"
|
|
31061
|
-
})
|
|
31338
|
+
identifier: readIdentifierField
|
|
31062
31339
|
});
|
|
31063
31340
|
var sessionResponse = external_exports.object({
|
|
31064
31341
|
anonId: external_exports.string().nullable().openapi({
|
|
@@ -31535,6 +31812,16 @@ var AliasDO = class extends DurableObject {
|
|
|
31535
31812
|
return { exists: true, objectId: this.ctx.id.toString(), assignment, databaseSize: this.ctx.storage.sql.databaseSize };
|
|
31536
31813
|
});
|
|
31537
31814
|
}
|
|
31815
|
+
async erase(trace) {
|
|
31816
|
+
return runInvocation({ name: "do.alias.erase", trace }, async () => {
|
|
31817
|
+
if (await this.record() === void 0) {
|
|
31818
|
+
return false;
|
|
31819
|
+
}
|
|
31820
|
+
await this.ctx.storage.deleteAll();
|
|
31821
|
+
this.assignment = void 0;
|
|
31822
|
+
return true;
|
|
31823
|
+
});
|
|
31824
|
+
}
|
|
31538
31825
|
async record() {
|
|
31539
31826
|
if (!this.loaded) {
|
|
31540
31827
|
this.assignment = await this.ctx.storage.get(ASSIGNMENT_KEY);
|
|
@@ -32311,6 +32598,19 @@ var relink = /* @__PURE__ */ __name(async (storage, env, anonId, globalId) => {
|
|
|
32311
32598
|
await storage.setAlarm(cleanupTarget(storage, Date.now(), lastActivityAt(storage.kv) ?? Date.now()));
|
|
32312
32599
|
}
|
|
32313
32600
|
}, "relink");
|
|
32601
|
+
var unlinkFromPerson = /* @__PURE__ */ __name((env, anonId, globalId) => {
|
|
32602
|
+
return traced("rpc global.unlink_anon", { attrs: { "global.id": globalId } }, () => {
|
|
32603
|
+
return globalStub(env, globalId).unlinkAnon(anonId, currentTraceContext());
|
|
32604
|
+
});
|
|
32605
|
+
}, "unlinkFromPerson");
|
|
32606
|
+
var eraseAnon = /* @__PURE__ */ __name(async (storage, env) => {
|
|
32607
|
+
const anonId = storedAnonId(storage.kv);
|
|
32608
|
+
const globalId = linkedGlobalId(storage.kv);
|
|
32609
|
+
if (anonId !== null && globalId !== null) {
|
|
32610
|
+
await unlinkFromPerson(env, anonId, globalId);
|
|
32611
|
+
}
|
|
32612
|
+
await storage.deleteAll();
|
|
32613
|
+
}, "eraseAnon");
|
|
32314
32614
|
var expireAnon = /* @__PURE__ */ __name(async (storage, env, staleActivity) => {
|
|
32315
32615
|
if (await standsDown(storage, staleActivity)) {
|
|
32316
32616
|
return false;
|
|
@@ -32319,9 +32619,7 @@ var expireAnon = /* @__PURE__ */ __name(async (storage, env, staleActivity) => {
|
|
|
32319
32619
|
const globalId = linkedGlobalId(storage.kv);
|
|
32320
32620
|
if (anonId !== null && globalId !== null) {
|
|
32321
32621
|
try {
|
|
32322
|
-
await
|
|
32323
|
-
return globalStub(env, globalId).unlinkAnon(anonId, currentTraceContext());
|
|
32324
|
-
});
|
|
32622
|
+
await unlinkFromPerson(env, anonId, globalId);
|
|
32325
32623
|
} catch (error61) {
|
|
32326
32624
|
addSpanEvent("expiry unlink failed", { level: "warn", attrs: { "anon.id": anonId, "global.id": globalId, error: String(error61) } });
|
|
32327
32625
|
await storage.setAlarm(Date.now() + CLEANUP_INTERVAL_MS);
|
|
@@ -32827,7 +33125,7 @@ var AnonDO = class extends DurableObject2 {
|
|
|
32827
33125
|
wiped = false;
|
|
32828
33126
|
// True while processAction holds ingestQueue, including the transform await.
|
|
32829
33127
|
ingestTurn = false;
|
|
32830
|
-
// Warm write-through mirrors reset together after expiry.
|
|
33128
|
+
// Warm write-through mirrors reset together after an expiry or an erase.
|
|
32831
33129
|
kvCache;
|
|
32832
33130
|
cachedStorage;
|
|
32833
33131
|
identifiersMirror = identifiersCache();
|
|
@@ -33466,6 +33764,17 @@ var AnonDO = class extends DurableObject2 {
|
|
|
33466
33764
|
});
|
|
33467
33765
|
});
|
|
33468
33766
|
}
|
|
33767
|
+
erasable(trace) {
|
|
33768
|
+
return runInvocation({ name: "do.anon.erasable", trace }, () => {
|
|
33769
|
+
return this.enqueue(async () => {
|
|
33770
|
+
if (await this.discardIfUnused()) {
|
|
33771
|
+
return null;
|
|
33772
|
+
}
|
|
33773
|
+
const identifiers = allIdentifiers(this.sql, this.identifiersMirror).map(({ type, value }) => ({ type, value }));
|
|
33774
|
+
return { globalId: linkedGlobalId(this.kv), identifiers };
|
|
33775
|
+
});
|
|
33776
|
+
});
|
|
33777
|
+
}
|
|
33469
33778
|
inspect(trace) {
|
|
33470
33779
|
return runInvocation({ name: "do.anon.inspect", trace }, () => {
|
|
33471
33780
|
return this.enqueue(async () => {
|
|
@@ -33486,6 +33795,25 @@ var AnonDO = class extends DurableObject2 {
|
|
|
33486
33795
|
});
|
|
33487
33796
|
});
|
|
33488
33797
|
}
|
|
33798
|
+
erase(trace) {
|
|
33799
|
+
return runInvocation({ name: "do.anon.erase", trace }, () => {
|
|
33800
|
+
return this.enqueue(async () => {
|
|
33801
|
+
if (await this.discardIfUnused()) {
|
|
33802
|
+
return false;
|
|
33803
|
+
}
|
|
33804
|
+
try {
|
|
33805
|
+
await eraseAnon(this.ctx.storage, this.graph);
|
|
33806
|
+
} finally {
|
|
33807
|
+
this.resetMirrors();
|
|
33808
|
+
}
|
|
33809
|
+
this.wiped = true;
|
|
33810
|
+
for (const socket of this.ctx.getWebSockets()) {
|
|
33811
|
+
socket.close(1e3, "erased");
|
|
33812
|
+
}
|
|
33813
|
+
return true;
|
|
33814
|
+
});
|
|
33815
|
+
});
|
|
33816
|
+
}
|
|
33489
33817
|
// Addressing an object runs the constructor's schema exec, so a call that never writes — a read, an
|
|
33490
33818
|
// inspect, a push or a snapshot for an id that was never used — would otherwise leave an empty object
|
|
33491
33819
|
// behind that no cleanup alarm ever collects. Every write path seeds meta before it stores anything,
|
|
@@ -33725,16 +34053,19 @@ var AnonDO = class extends DurableObject2 {
|
|
|
33725
34053
|
try {
|
|
33726
34054
|
this.wiped = await expireAnon(this.ctx.storage, this.graph, staleActivity);
|
|
33727
34055
|
} finally {
|
|
33728
|
-
this.
|
|
33729
|
-
this.cleanupAlarm = void 0;
|
|
33730
|
-
this.identifiersMirror.reset();
|
|
33731
|
-
this.conversionsMirror.reset();
|
|
33732
|
-
this.customPropsMirror.reset();
|
|
33733
|
-
this.captureMirror.reset();
|
|
33734
|
-
this.contextMirror.reset();
|
|
34056
|
+
this.resetMirrors();
|
|
33735
34057
|
}
|
|
33736
34058
|
});
|
|
33737
34059
|
}
|
|
34060
|
+
resetMirrors() {
|
|
34061
|
+
this.kvCache.clear();
|
|
34062
|
+
this.cleanupAlarm = void 0;
|
|
34063
|
+
this.identifiersMirror.reset();
|
|
34064
|
+
this.conversionsMirror.reset();
|
|
34065
|
+
this.customPropsMirror.reset();
|
|
34066
|
+
this.captureMirror.reset();
|
|
34067
|
+
this.contextMirror.reset();
|
|
34068
|
+
}
|
|
33738
34069
|
revive() {
|
|
33739
34070
|
if (this.wiped) {
|
|
33740
34071
|
applyMigrations(this.ctx.storage, ANON_MIGRATIONS);
|
|
@@ -33976,7 +34307,9 @@ var GlobalDO = class extends DurableObject3 {
|
|
|
33976
34307
|
}
|
|
33977
34308
|
async unlinkAnon(anonId, trace) {
|
|
33978
34309
|
return runInvocation({ name: "do.global.unlink_anon", trace, attrs: { "anon.id": anonId } }, async () => {
|
|
33979
|
-
this.
|
|
34310
|
+
if (await this.discardIfUnused()) {
|
|
34311
|
+
return;
|
|
34312
|
+
}
|
|
33980
34313
|
unlinkAnon(this.sql, anonId);
|
|
33981
34314
|
});
|
|
33982
34315
|
}
|
|
@@ -34001,6 +34334,30 @@ var GlobalDO = class extends DurableObject3 {
|
|
|
34001
34334
|
return linkedAnonsPage(this.sql, afterRowId, limit);
|
|
34002
34335
|
});
|
|
34003
34336
|
}
|
|
34337
|
+
async erasable(trace) {
|
|
34338
|
+
return runInvocation({ name: "do.global.erasable", trace }, async () => {
|
|
34339
|
+
if (await this.discardIfUnused()) {
|
|
34340
|
+
return null;
|
|
34341
|
+
}
|
|
34342
|
+
const identifiers = allIdentifiers2(this.sql, this.identifiersMirror).map(({ type, value }) => ({ type, value }));
|
|
34343
|
+
return { anonIds: allLinkedAnons(this.sql), identifiers };
|
|
34344
|
+
});
|
|
34345
|
+
}
|
|
34346
|
+
async erase(trace) {
|
|
34347
|
+
return runInvocation({ name: "do.global.erase", trace }, async () => {
|
|
34348
|
+
if (await this.discardIfUnused()) {
|
|
34349
|
+
return false;
|
|
34350
|
+
}
|
|
34351
|
+
try {
|
|
34352
|
+
await this.ctx.storage.deleteAll();
|
|
34353
|
+
} finally {
|
|
34354
|
+
this.kvCache.clear();
|
|
34355
|
+
this.identifiersMirror = identifiersCache2();
|
|
34356
|
+
}
|
|
34357
|
+
this.wiped = true;
|
|
34358
|
+
return true;
|
|
34359
|
+
});
|
|
34360
|
+
}
|
|
34004
34361
|
async inspect(trace) {
|
|
34005
34362
|
return runInvocation({ name: "do.global.inspect", trace }, async () => {
|
|
34006
34363
|
if (await this.discardIfUnused()) {
|