@cosmicdrift/kumiko-bundled-features 0.333.0 → 0.335.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/dist/admin-shell/overview-panels.js +2 -2
- package/dist/agent-tools/agent-doc-lint.d.ts +1 -0
- package/dist/agent-tools/agent-doc-lint.js +33 -3
- package/dist/agent-tools/agent-manifest.js +47 -6
- package/dist/agent-tools/filter-ops.d.ts +2 -0
- package/dist/agent-tools/filter-ops.js +4 -0
- package/dist/agent-tools/tool-catalog.js +1 -4
- package/dist/agent-tools/tool-dispatch.js +1 -4
- package/dist/audit/constants.d.ts +1 -1
- package/dist/audit/constants.js +1 -1
- package/dist/audit/handlers/list.query.js +4 -3
- package/dist/auth-email-password/handlers/change-password.write.js +2 -0
- package/dist/auth-email-password/handlers/invite-create.write.js +12 -2
- package/dist/auth-email-password/handlers/login.write.js +2 -0
- package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
- package/dist/auth-email-password/i18n.js +2 -0
- package/dist/auth-email-password/web/auth-client.d.ts +1 -0
- package/dist/auth-email-password/web/auth-client.js +1 -1
- package/dist/auth-email-password/web/auth-gate.js +6 -8
- package/dist/auth-email-password/web/index.d.ts +1 -1
- package/dist/auth-email-password/web/index.js +1 -1
- package/dist/auth-email-password/web/invite-accept-screen.js +16 -12
- package/dist/auth-email-password/web/login-screen.js +1 -1
- package/dist/auth-email-password/web/session-bootstrap-error.d.ts +5 -1
- package/dist/auth-email-password/web/session-bootstrap-error.js +2 -2
- package/dist/auth-email-password/web/session.d.ts +4 -0
- package/dist/auth-email-password/web/session.js +15 -0
- package/dist/auth-mfa/feature.js +3 -2
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +2 -2
- package/dist/auth-mfa/handlers/verify.write.js +2 -0
- package/dist/auth-mfa/hmac-token-codec.js +3 -0
- package/dist/auth-mfa/mfa-challenge-token.js +4 -0
- package/dist/auth-mfa/mfa-preauth-setup-token.js +3 -0
- package/dist/auth-mfa/schema/user-mfa.d.ts +6 -0
- package/dist/auth-mfa/web/mfa-client.d.ts +1 -1
- package/dist/auth-mfa/web/mfa-client.js +4 -10
- package/dist/billing-foundation/billing-info-query.js +1 -1
- package/dist/billing-foundation/checkout-core.d.ts +5 -5
- package/dist/billing-foundation/checkout-core.js +10 -6
- package/dist/billing-foundation/entities.d.ts +8 -0
- package/dist/billing-foundation/handlers/switch-plan.write.js +5 -8
- package/dist/billing-foundation/projection.d.ts +8 -0
- package/dist/cap-counter/book-cap-usage.js +15 -5
- package/dist/cap-counter/enforce-cap.js +9 -3
- package/dist/cap-counter/entity.d.ts +1 -0
- package/dist/cap-counter/feature.js +3 -2
- package/dist/cap-counter/i18n.d.ts +1 -0
- package/dist/cap-counter/i18n.js +6 -5
- package/dist/cap-overview/handlers/caps-usage.query.js +9 -16
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +41 -15
- package/dist/cap-overview/i18n.js +5 -0
- package/dist/cap-overview/web/cap-cards-panel.js +4 -1
- package/dist/cap-overview/web/cap-usage-bar.js +1 -1
- package/dist/channel-email/email-channel.js +12 -1
- package/dist/channel-in-app/tables.js +2 -6
- package/dist/compliance-profiles/handlers/sub-processors.query.js +1 -1
- package/dist/compliance-profiles/schema/profile-selection.d.ts +2 -2
- package/dist/config/db/queries/resolver.js +3 -1
- package/dist/config/handlers/set.write.js +8 -4
- package/dist/config/table.d.ts +6 -0
- package/dist/config/web/i18n.js +13 -4
- package/dist/config/write-helpers.d.ts +1 -1
- package/dist/config/write-helpers.js +11 -5
- package/dist/crypto-shredding/handlers/forget-subject.write.js +15 -8
- package/dist/custom-fields/constants.js +1 -4
- package/dist/custom-fields/entity.d.ts +4 -0
- package/dist/data-retention/resolve-for-tenant.d.ts +2 -3
- package/dist/data-retention/run-retention-cleanup.js +100 -44
- package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -0
- package/dist/delivery/tables.d.ts +6 -0
- package/dist/delivery/types.d.ts +2 -1
- package/dist/delivery/types.js +7 -0
- package/dist/delivery/unsubscribe.js +5 -11
- package/dist/derivatives-sharp/render.js +27 -9
- package/dist/document-ingest-foundation/entity.d.ts +4 -0
- package/dist/document-ingest-foundation/feature.js +5 -5
- package/dist/document-ingest-foundation/providers.d.ts +1 -0
- package/dist/document-ingest-foundation/providers.js +6 -0
- package/dist/document-ingest-foundation/write-document-extract.d.ts +2 -2
- package/dist/document-ingest-foundation/write-document-extract.js +10 -0
- package/dist/feature-toggles/global-feature-state-table.js +2 -7
- package/dist/feature-toggles/toggle-sync-signal.d.ts +2 -1
- package/dist/feature-toggles/toggle-sync-signal.js +3 -2
- package/dist/file-provider-s3/feature.js +1 -1
- package/dist/files-tenant-data/index.js +3 -2
- package/dist/folders/entity.d.ts +8 -0
- package/dist/folders/handlers/clear-folder.write.js +4 -11
- package/dist/folders/handlers/set-folder.write.js +4 -10
- package/dist/form-draft/entity.d.ts +2 -0
- package/dist/form-draft/feature.js +3 -2
- package/dist/form-draft/handlers/discard.write.js +7 -8
- package/dist/form-draft/handlers/get.query.js +7 -1
- package/dist/foundation-shared/host-allowlist.d.ts +4 -0
- package/dist/foundation-shared/host-allowlist.js +14 -0
- package/dist/foundation-shared/index.d.ts +1 -0
- package/dist/foundation-shared/index.js +1 -0
- package/dist/foundation-shared/mail-host-policy.d.ts +0 -2
- package/dist/foundation-shared/mail-host-policy.js +3 -13
- package/dist/inbound-mail-foundation/connect-routes.js +7 -5
- package/dist/inbound-mail-foundation/entities.d.ts +25 -0
- package/dist/inbound-mail-foundation/projection.d.ts +20 -0
- package/dist/inbound-mail-foundation/watch-supervisor.js +47 -43
- package/dist/jobs/handlers/list.query.d.ts +7 -2
- package/dist/jobs/handlers/list.query.js +9 -2
- package/dist/jobs/handlers/retry.write.js +3 -2
- package/dist/jobs/handlers/tenant-failures.query.js +3 -9
- package/dist/jobs/job-run-logger.js +18 -2
- package/dist/jobs/job-run-table.d.ts +6 -0
- package/dist/jobs/tenant-job-failure-table.js +2 -6
- package/dist/ledger/entity.d.ts +16 -3
- package/dist/ledger/handlers/confirm-schedule-period.write.js +2 -2
- package/dist/ledger/handlers/reverse-transaction.write.js +2 -2
- package/dist/ledger/subject-reference.d.ts +4 -0
- package/dist/ledger/subject-reference.js +7 -0
- package/dist/legal-pages/feature.js +8 -1
- package/dist/managed-pages/handlers/branding.query.js +1 -1
- package/dist/managed-pages/handlers/by-slug.query.js +1 -1
- package/dist/managed-pages/handlers/by-tenant-published.query.js +1 -1
- package/dist/managed-pages/table.d.ts +12 -0
- package/dist/metrics/compute.js +7 -1
- package/dist/metrics/window.js +5 -0
- package/dist/notes-history/entity.d.ts +12 -0
- package/dist/notes-history/handlers/add-note.write.js +4 -9
- package/dist/notes-history-user-data/hooks.js +8 -1
- package/dist/personal-access-tokens/constants.d.ts +1 -0
- package/dist/personal-access-tokens/constants.js +1 -0
- package/dist/personal-access-tokens/feature.js +2 -2
- package/dist/personal-access-tokens/handlers/create.write.js +2 -2
- package/dist/personal-access-tokens/handlers/revoke.write.js +2 -2
- package/dist/personal-access-tokens/i18n.js +12 -13
- package/dist/personal-access-tokens/schema/api-token.d.ts +6 -0
- package/dist/personal-access-tokens/schema/api-token.js +2 -1
- package/dist/personal-access-tokens/screens.js +5 -1
- package/dist/rate-limiting/feature.js +2 -0
- package/dist/rate-limiting/handlers/bucket-access.js +15 -7
- package/dist/rate-limiting/i18n.d.ts +10 -0
- package/dist/rate-limiting/i18n.js +10 -0
- package/dist/secrets/feature.js +3 -2
- package/dist/secrets/table.d.ts +1 -0
- package/dist/seo/handlers/seo-config.query.js +1 -1
- package/dist/sessions/constants.d.ts +1 -0
- package/dist/sessions/constants.js +1 -0
- package/dist/sessions/feature.js +5 -3
- package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -0
- package/dist/sessions/handlers/revoke-all-for-user.write.js +12 -2
- package/dist/sessions/handlers/revoke.write.js +2 -2
- package/dist/sessions/schema/user-session.d.ts +4 -0
- package/dist/sessions/schema/user-session.js +2 -1
- package/dist/sessions/screens.js +5 -1
- package/dist/sessions/session-callbacks.js +2 -2
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/lockout-counter.js +1 -1
- package/dist/shared/parent-visibility.d.ts +5 -0
- package/dist/shared/parent-visibility.js +17 -1
- package/dist/shared/row-bound-grant.js +20 -9
- package/dist/shared/single-use-token-store.js +5 -13
- package/dist/step-dispatcher/webhook-runner.d.ts +0 -2
- package/dist/step-dispatcher/webhook-runner.js +18 -17
- package/dist/subscription-mollie/plugin-methods.d.ts +3 -2
- package/dist/subscription-mollie/plugin-methods.js +7 -1
- package/dist/subscription-mollie/verify-webhook.js +6 -0
- package/dist/subscription-stripe/feature.js +3 -3
- package/dist/subscription-stripe/plugin-methods.js +25 -6
- package/dist/subscription-stripe/verify-webhook.js +13 -6
- package/dist/tags/entity.d.ts +9 -0
- package/dist/tags/handlers/assign-tag.write.js +4 -10
- package/dist/tags/handlers/remove-tag.write.js +4 -11
- package/dist/template-resolver/api.d.ts +2 -1
- package/dist/template-resolver/api.js +1 -1
- package/dist/template-resolver/handlers/by-slug.query.d.ts +1 -1
- package/dist/template-resolver/handlers/by-slug.query.js +2 -2
- package/dist/template-resolver/handlers/by-tenant.query.d.ts +3 -2
- package/dist/template-resolver/handlers/by-tenant.query.js +2 -2
- package/dist/template-resolver/handlers/collection-item.query.d.ts +1 -1
- package/dist/template-resolver/handlers/collection-list.query.d.ts +1 -1
- package/dist/template-resolver/handlers/collection-shared.d.ts +3 -2
- package/dist/template-resolver/handlers/collection-shared.js +1 -1
- package/dist/template-resolver/handlers/find-by-id.query.d.ts +1 -1
- package/dist/template-resolver/handlers/find-by-id.query.js +1 -1
- package/dist/template-resolver/handlers/list.query.d.ts +1 -1
- package/dist/template-resolver/handlers/list.query.js +1 -1
- package/dist/template-resolver/seeding.js +41 -39
- package/dist/template-resolver/table.d.ts +26 -13
- package/dist/template-resolver/testing.js +2 -2
- package/dist/template-resolver/user-content-table.d.ts +16 -9
- package/dist/template-resolver/web/client-plugin.d.ts +1 -1
- package/dist/template-resolver-user-data/hooks.js +1 -1
- package/dist/tenant/cancel-pending-invitation.d.ts +8 -0
- package/dist/tenant/cancel-pending-invitation.js +22 -0
- package/dist/tenant/feature.js +4 -2
- package/dist/tenant/handlers/cancel-invitation.write.js +6 -21
- package/dist/tenant/handlers/member-directory.query.d.ts +1 -0
- package/dist/tenant/handlers/member-directory.query.js +17 -4
- package/dist/tenant/handlers/remove-member.write.js +9 -14
- package/dist/tenant/handlers/team-list.query.js +2 -2
- package/dist/tenant/handlers/tenant-directory.query.d.ts +1 -0
- package/dist/tenant/handlers/tenant-directory.query.js +13 -3
- package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
- package/dist/tenant/handlers/update-member-roles.write.js +28 -12
- package/dist/tenant/i18n.js +4 -0
- package/dist/tenant/index.d.ts +1 -1
- package/dist/tenant/index.js +1 -1
- package/dist/tenant/invitation-table.d.ts +8 -2
- package/dist/tenant/last-tenant-admin.d.ts +1 -1
- package/dist/tenant/last-tenant-admin.js +5 -3
- package/dist/tenant/membership-table.d.ts +4 -0
- package/dist/tenant/schema/tenant.d.ts +8 -2
- package/dist/tenant/seeding.d.ts +4 -0
- package/dist/tenant/seeding.js +9 -2
- package/dist/tenant-lifecycle/boot-checks.d.ts +1 -0
- package/dist/tenant-lifecycle/boot-checks.js +27 -1
- package/dist/tenant-lifecycle/feature.js +2 -1
- package/dist/tenant-lifecycle/stages.js +2 -2
- package/dist/tenant-settings/feature.js +9 -6
- package/dist/tier-engine/entity.d.ts +2 -0
- package/dist/tier-engine/feature.js +3 -2
- package/dist/tier-engine/tier-resolver.d.ts +2 -0
- package/dist/user/command-schemas.d.ts +2 -2
- package/dist/user/handlers/create.write.d.ts +1 -1
- package/dist/user/handlers/create.write.js +8 -2
- package/dist/user/handlers/update.write.d.ts +1 -1
- package/dist/user/handlers/update.write.js +8 -2
- package/dist/user/schema/user.d.ts +14 -2
- package/dist/user-data-rights/db/queries/export-jobs.d.ts +2 -0
- package/dist/user-data-rights/feature.js +22 -9
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +4 -7
- package/dist/user-data-rights/handlers/deletion-grace-period.d.ts +3 -2
- package/dist/user-data-rights/handlers/deletion-grace-period.js +30 -8
- package/dist/user-data-rights/handlers/download-by-token.query.js +1 -1
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +1 -1
- package/dist/user-data-rights/handlers/request-deletion.write.js +3 -6
- package/dist/user-data-rights/lib/update-user-lifecycle.js +7 -14
- package/dist/user-data-rights/run-export-jobs.d.ts +1 -0
- package/dist/user-data-rights/run-export-jobs.js +74 -41
- package/dist/user-data-rights/run-forget-cleanup.js +2 -2
- package/dist/user-data-rights/run-user-export.js +8 -4
- package/dist/user-data-rights/schema/download-attempt.d.ts +14 -0
- package/dist/user-data-rights/schema/download-token.d.ts +8 -0
- package/dist/user-data-rights/schema/export-job.d.ts +8 -2
- package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +4 -1
- package/dist/user-profile/feature.js +6 -1
- package/dist/user-profile/handlers/change-email.write.js +2 -0
- package/dist/workflow-runner/db/queries/due-runs.js +6 -9
- package/dist/workflow-runner/event-subscriber.js +29 -9
- package/dist/workflow-runner/handlers/resume-run.write.js +8 -5
- package/dist/workflow-runner/pending-projection.js +8 -1
- package/package.json +11 -9
- package/src/agent-tools/changes.json +12 -0
- package/src/auth-email-password/changes.json +18 -0
- package/src/auth-mfa/changes.json +6 -0
- package/src/billing-foundation/changes.json +7 -0
- package/src/cap-counter/changes.json +7 -0
- package/src/cap-overview/changes.json +12 -0
- package/src/channel-email/changes.json +6 -0
- package/src/config/changes.json +6 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/data-retention/changes.json +12 -0
- package/src/delivery/changes.json +7 -0
- package/src/derivatives-sharp/changes.json +11 -0
- package/src/document-ingest-foundation/changes.json +12 -0
- package/src/inbound-mail-foundation/changes.json +12 -0
- package/src/jobs/changes.json +13 -0
- package/src/legal-pages/changes.json +8 -1
- package/src/managed-pages/changes.json +5 -0
- package/src/metrics/changes.json +6 -0
- package/src/rate-limiting/changes.json +5 -0
- package/src/secrets/changes.json +7 -0
- package/src/sessions/changes.json +5 -0
- package/src/shared/changes.json +6 -0
- package/src/step-dispatcher/changes.json +5 -0
- package/src/subscription-mollie/changes.json +7 -0
- package/src/subscription-stripe/changes.json +11 -0
- package/src/template-resolver/changes.json +7 -0
- package/src/tenant/changes.json +29 -0
- package/src/user-data-rights/changes.json +22 -0
- package/src/workflow-runner/changes.json +6 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { USER_STATUS, userTable } from "../../user/index.js";
|
|
5
5
|
import { redeemDeletionToken } from "../deletion-token.js";
|
|
6
|
-
import { startDeletionGracePeriod } from "./deletion-grace-period.js";
|
|
6
|
+
import { resolveGracePeriod, startDeletionGracePeriod } from "./deletion-grace-period.js";
|
|
7
7
|
// Generischer 422 für jeden Token-Fehlerpfad (malformed / bad_signature /
|
|
8
8
|
// expired / kein Secret) — kein Signal ob ein Token zu einem User gehört.
|
|
9
9
|
function invalidToken() {
|
|
@@ -55,11 +55,8 @@ export function createConfirmDeletionByTokenHandler(opts = {}) {
|
|
|
55
55
|
"SYSTEM_TENANT_ID user stream.",
|
|
56
56
|
},
|
|
57
57
|
agent: { expose: false },
|
|
58
|
-
rateLimit: { per: "ip", limit: 10, windowSeconds: 60 },
|
|
58
|
+
rateLimit: { per: "ip+handler", limit: 10, windowSeconds: 60 },
|
|
59
59
|
handler: async (event, ctx) => {
|
|
60
|
-
// @cast-boundary engine-payload — queryAs returns unknown, narrowed to
|
|
61
|
-
// the compliance-profile shape.
|
|
62
|
-
const profile = (await ctx.queryAs(createSystemUser(event.user.tenantId), "compliance-profiles:query:for-tenant", {}));
|
|
63
60
|
let gracePeriodEndIso;
|
|
64
61
|
// The row's requestId is part of the verify key, so a token from a
|
|
65
62
|
// cancelled or superseded cycle fails. Every error path ends in the same
|
|
@@ -71,7 +68,7 @@ export function createConfirmDeletionByTokenHandler(opts = {}) {
|
|
|
71
68
|
secret: opts.deletionTokenSecret,
|
|
72
69
|
loadPendingRequestId: (userId) => readPendingDeletionRequestId(ctx, userId),
|
|
73
70
|
commitDeletion: async (userId, requestId) => {
|
|
74
|
-
const res = await startDeletionGracePeriod(ctx, userId,
|
|
71
|
+
const res = await startDeletionGracePeriod(ctx, userId, () => resolveGracePeriod(ctx, event.user.tenantId), ctx.db.unsafeRaw("appends the user lifecycle event on the SYSTEM_TENANT_ID user stream"), { pendingDeletionRequestId: requestId });
|
|
75
72
|
if (!res.ok)
|
|
76
73
|
return false;
|
|
77
74
|
gracePeriodEndIso = res.gracePeriodEnd.toString();
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type DurationSpec } from "@cosmicdrift/kumiko-framework/compliance";
|
|
2
2
|
import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
|
|
3
|
-
import type
|
|
3
|
+
import { type HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
5
5
|
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
6
6
|
type Instant = InstanceType<ReturnType<typeof getTemporal>["Instant"]>;
|
|
7
|
+
export declare function resolveGracePeriod(ctx: HandlerContext, tenantId: string): Promise<DurationSpec>;
|
|
7
8
|
export type StartGracePeriodResult = {
|
|
8
9
|
readonly ok: true;
|
|
9
10
|
readonly gracePeriodEnd: Instant;
|
|
@@ -13,5 +14,5 @@ export type StartGracePeriodResult = {
|
|
|
13
14
|
readonly ok: false;
|
|
14
15
|
readonly error: UnprocessableError;
|
|
15
16
|
};
|
|
16
|
-
export declare function startDeletionGracePeriod(ctx: HandlerContext, userId: string,
|
|
17
|
+
export declare function startDeletionGracePeriod(ctx: HandlerContext, userId: string, resolveGracePeriodSpec: () => Promise<DurationSpec>, lifecycleRunner: DbRunner, additionalExpect?: Readonly<Record<string, string | number | boolean | null>>): Promise<StartGracePeriodResult>;
|
|
17
18
|
export {};
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import { addDurationSpec } from "@cosmicdrift/kumiko-framework/compliance";
|
|
1
|
+
import { addDurationSpec, } from "@cosmicdrift/kumiko-framework/compliance";
|
|
2
|
+
import { createSystemUser, declareEscapeHatch, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
3
|
import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
4
|
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
4
5
|
import { decryptStoredPii } from "../../shared/index.js";
|
|
5
6
|
import { USER_STATUS, userTable } from "../../user/index.js";
|
|
6
7
|
import { updateUserLifecycle } from "../lib/update-user-lifecycle.js";
|
|
8
|
+
// Single trust-boundary cast for the compliance-profile lookup: the query
|
|
9
|
+
// handler's declared return type is EffectiveComplianceProfile, but queryAs
|
|
10
|
+
// only hands back unknown. Needs the calling handler's escapeHatch (system
|
|
11
|
+
// queryAs).
|
|
12
|
+
export async function resolveGracePeriod(ctx, tenantId) {
|
|
13
|
+
declareEscapeHatch({
|
|
14
|
+
reason: "reads the tenant compliance profile via queryAs(SYSTEM, ...) to compute the grace period end; the calling user's own identity has no read access to that tenant-config projection",
|
|
15
|
+
});
|
|
16
|
+
const profile = (await ctx.queryAs(createSystemUser(tenantId), "compliance-profiles:query:for-tenant", {})); // @cast-boundary engine-payload
|
|
17
|
+
return profile.profile.userRights.gracePeriod;
|
|
18
|
+
}
|
|
7
19
|
// Flips an active user to DeletionRequested and sets gracePeriodEnd from the
|
|
8
20
|
// caller-supplied grace period. Shared between the authenticated
|
|
9
21
|
// request-deletion path (event.user) and the anonymous confirm-by-token path
|
|
@@ -13,7 +25,7 @@ import { updateUserLifecycle } from "../lib/update-user-lifecycle.js";
|
|
|
13
25
|
// ctx.db.global(userTable); only the grace period duration is tenant-configured.
|
|
14
26
|
// That read only supplies email/locale for the caller's notification — it is
|
|
15
27
|
// NOT the transition's guard. The guard is `expect: { status: Active }` on
|
|
16
|
-
// the lifecycle write itself
|
|
28
|
+
// the lifecycle write itself: the executor re-checks it against a
|
|
17
29
|
// fresh row right before writing, so a concurrent caller that already moved
|
|
18
30
|
// the user off Active is rejected even though this read saw Active.
|
|
19
31
|
//
|
|
@@ -31,11 +43,13 @@ import { updateUserLifecycle } from "../lib/update-user-lifecycle.js";
|
|
|
31
43
|
// true). No-op for the authenticated request-deletion path, which never set
|
|
32
44
|
// a pendingDeletionRequestId to begin with.
|
|
33
45
|
//
|
|
34
|
-
// `
|
|
35
|
-
// require an escalation (reading the tenant compliance profile,
|
|
36
|
-
// the SYSTEM_TENANT_ID user stream) that only the declaring
|
|
37
|
-
// escapeHatch covers.
|
|
38
|
-
|
|
46
|
+
// `resolveGracePeriodSpec` and `lifecycleRunner` are supplied by the caller:
|
|
47
|
+
// both require an escalation (reading the tenant compliance profile,
|
|
48
|
+
// appending to the SYSTEM_TENANT_ID user stream) that only the declaring
|
|
49
|
+
// handler's escapeHatch covers. The grace period is a lazy provider so the
|
|
50
|
+
// privileged compliance-profile query only runs for a user that is still
|
|
51
|
+
// Active, not for replayed tokens or already-requested deletions.
|
|
52
|
+
export async function startDeletionGracePeriod(ctx, userId, resolveGracePeriodSpec, lifecycleRunner, additionalExpect) {
|
|
39
53
|
const userRow = await ctx.db
|
|
40
54
|
.global(userTable)
|
|
41
55
|
.fetchOne({ id: userId });
|
|
@@ -47,8 +61,16 @@ export async function startDeletionGracePeriod(ctx, userId, gracePeriod, lifecyc
|
|
|
47
61
|
}),
|
|
48
62
|
};
|
|
49
63
|
}
|
|
64
|
+
if (userRow["status"] !== USER_STATUS.Active) {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
error: new UnprocessableError("user_not_in_active_state", {
|
|
68
|
+
details: { currentStatus: userRow["status"] },
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
50
72
|
const T = getTemporal();
|
|
51
|
-
const gracePeriodEnd = addDurationSpec(T.Now.instant(),
|
|
73
|
+
const gracePeriodEnd = addDurationSpec(T.Now.instant(), await resolveGracePeriodSpec());
|
|
52
74
|
const { applied } = await updateUserLifecycle(lifecycleRunner, userId, { status: USER_STATUS.DeletionRequested, gracePeriodEnd, pendingDeletionRequestId: null }, { expect: { status: USER_STATUS.Active, ...additionalExpect } });
|
|
53
75
|
if (!applied) {
|
|
54
76
|
return {
|
|
@@ -56,7 +56,7 @@ export const downloadByTokenQuery = defineQueryHandler({
|
|
|
56
56
|
// 30 attempts/min/IP reicht fuer legitime User (mehrere Klicks bei
|
|
57
57
|
// Connection-Abbruch); blockiert automatisierte Probing-Loops.
|
|
58
58
|
// Memory `feedback_security_default_on`.
|
|
59
|
-
rateLimit: { per: "ip", limit: 30, windowSeconds: 60 },
|
|
59
|
+
rateLimit: { per: "ip+handler", limit: 30, windowSeconds: 60 },
|
|
60
60
|
escapeHatch: {
|
|
61
61
|
reason: DOWNLOAD_BY_TOKEN_REASON,
|
|
62
62
|
},
|
|
@@ -34,7 +34,7 @@ export function createRequestDeletionByEmailHandler(opts = {}) {
|
|
|
34
34
|
// Mails a deletion link to any address the caller names.
|
|
35
35
|
agent: { risk: "high" },
|
|
36
36
|
// Defense-in-depth gegen Email-Probing auf dem anonymen Endpoint.
|
|
37
|
-
rateLimit: { per: "ip", limit: 10, windowSeconds: 60 },
|
|
37
|
+
rateLimit: { per: "ip+handler", limit: 10, windowSeconds: 60 },
|
|
38
38
|
escapeHatch: {
|
|
39
39
|
reason: APPEND_LIFECYCLE_EVENT_REASON,
|
|
40
40
|
},
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createTransportForTenant } from "@cosmicdrift/kumiko-bundled-features/mail-foundation";
|
|
2
|
-
import {
|
|
2
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
4
|
import * as z from "zod";
|
|
5
5
|
import { USER_STATUS } from "../../user/index.js";
|
|
6
6
|
import { isMailTransportAvailable, makeDefaultDeletionRequestedEmail, } from "../lib/default-mailers.js";
|
|
7
|
-
import { startDeletionGracePeriod } from "./deletion-grace-period.js";
|
|
7
|
+
import { resolveGracePeriod, startDeletionGracePeriod } from "./deletion-grace-period.js";
|
|
8
8
|
// POST /api/user/request-deletion (S2.U5a) — DSGVO Art. 17 Forget-Antrag.
|
|
9
9
|
// Flippt status=Active → deletionRequested, setzt gracePeriodEnd aus dem
|
|
10
10
|
// Compliance-Profile (geteilte Logik: startDeletionGracePeriod). Account-
|
|
@@ -29,10 +29,7 @@ export function createRequestDeletionHandler(opts = {}) {
|
|
|
29
29
|
description: "Starts the GDPR Art. 17 deletion of the calling user's own account by arming the grace period from the tenant compliance profile and mailing a confirmation, after which only cancel-deletion can stop the erasure.",
|
|
30
30
|
agent: { risk: "high" },
|
|
31
31
|
handler: async (event, ctx) => {
|
|
32
|
-
|
|
33
|
-
// the compliance-profile shape.
|
|
34
|
-
const profile = (await ctx.queryAs(createSystemUser(event.user.tenantId), "compliance-profiles:query:for-tenant", {}));
|
|
35
|
-
const res = await startDeletionGracePeriod(ctx, event.user.id, profile.profile.userRights.gracePeriod, ctx.db.unsafeRaw("appends the user lifecycle event on the SYSTEM_TENANT_ID user stream"));
|
|
32
|
+
const res = await startDeletionGracePeriod(ctx, event.user.id, () => resolveGracePeriod(ctx, event.user.tenantId), ctx.db.unsafeRaw("appends the user lifecycle event on the SYSTEM_TENANT_ID user stream"));
|
|
36
33
|
if (!res.ok)
|
|
37
34
|
return writeFailure(res.error);
|
|
38
35
|
const { gracePeriodEnd, userEmail, userLocale } = res;
|
|
@@ -26,25 +26,18 @@ const userExecutor = createEventStoreExecutor(userTable, userEntity, { entityNam
|
|
|
26
26
|
// longer held (precondition_failed) or a concurrent writer won the race on
|
|
27
27
|
// the same stream version (version_conflict) — both mean "someone else's
|
|
28
28
|
// transition already landed", the expected outcome for a caller that opted
|
|
29
|
-
// into `expect`. Any other failure, or a failure with no `expect` set
|
|
30
|
-
//
|
|
31
|
-
//
|
|
29
|
+
// into `expect`. Any other failure, or a failure with no `expect` set, still
|
|
30
|
+
// throws — those callers never checked a return value, so silently dropping
|
|
31
|
+
// their write would be silent data loss.
|
|
32
32
|
export async function updateUserLifecycle(conn, userId, changes, options) {
|
|
33
33
|
// user ist systemStream (#497): der Executor-Choke-Point addressiert den
|
|
34
34
|
// Stream immer auf SYSTEM_TENANT_ID — ein Rescope auf die row-tenant_id
|
|
35
35
|
// waere wirkungslos. "system"-Mode, damit loadById auch Legacy-Rows findet,
|
|
36
36
|
// deren tenant_id noch vor dem #762-Backfill-Rebuild steht.
|
|
37
|
-
// skipOptimisticLock
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// round-trip — none of them read-then-hold a row version to pass as
|
|
42
|
-
// `payload.version`, so the executor's version gate would reject every
|
|
43
|
-
// call outright without it (`update()` requires `payload.version` unless
|
|
44
|
-
// skipOptimisticLock is set). #3024 replaces the safety that decision gave
|
|
45
|
-
// up with the purpose-built `expect:` precondition above, checked fresh at
|
|
46
|
-
// write time — the mechanism now genuinely matches the caller's shape
|
|
47
|
-
// (a business-field guard) instead of a repurposed version check.
|
|
37
|
+
// skipOptimisticLock: every caller is a server-side business transition
|
|
38
|
+
// (restrict/lift-restriction/grace-period/cancel/forget) that holds no row
|
|
39
|
+
// version to pass as `payload.version`, which update() requires otherwise.
|
|
40
|
+
// Callers needing a guard use `options.expect` instead.
|
|
48
41
|
const tenantDb = createTenantDb(conn, SYSTEM_TENANT_ID, "system");
|
|
49
42
|
const result = await userExecutor.update({ id: userId, changes }, createSystemUser(SYSTEM_TENANT_ID), tenantDb, { skipOptimisticLock: true, ...(options?.expect && { expect: options.expect }) });
|
|
50
43
|
if (result.isSuccess)
|
|
@@ -5,6 +5,7 @@ import type { MetricsHandle } from "@cosmicdrift/kumiko-framework/observability"
|
|
|
5
5
|
import type { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
6
6
|
type Instant = InstanceType<ReturnType<typeof getTemporal>["Instant"]>;
|
|
7
7
|
export declare const EXPORT_CLEANUP_BACKLOG_AGE_METRIC = "export_cleanup_backlog_age";
|
|
8
|
+
export declare const EXPORT_CLEANUP_LAST_RUN_TIMESTAMP_METRIC = "export_cleanup_last_run_timestamp";
|
|
8
9
|
export declare const tokenCrud: import("@cosmicdrift/kumiko-types/event-store-executor-types").EventStoreExecutor;
|
|
9
10
|
/**
|
|
10
11
|
* Notification-Callback fuer den done-Pfad. Pattern matched
|
|
@@ -62,6 +62,10 @@ import { generateDownloadToken } from "./token-helpers.js";
|
|
|
62
62
|
// No "_seconds"/"_total" suffix: validateMetricName rejects both on a gauge.
|
|
63
63
|
// Unit lives in the r.metric() `unit: "seconds"` declaration instead.
|
|
64
64
|
export const EXPORT_CLEANUP_BACKLOG_AGE_METRIC = "export_cleanup_backlog_age";
|
|
65
|
+
// Unix seconds of the last storage-cleanup pass that ran to completion. A
|
|
66
|
+
// gauge keeps its last value in-process (no TTL), so a dead cron does not make
|
|
67
|
+
// the backlog gauge disappear — alert on `time() - this > interval + buffer`.
|
|
68
|
+
export const EXPORT_CLEANUP_LAST_RUN_TIMESTAMP_METRIC = "export_cleanup_last_run_timestamp";
|
|
65
69
|
const crud = createEventStoreExecutor(exportJobsTable, exportJobEntity, {
|
|
66
70
|
entityName: "export-job",
|
|
67
71
|
});
|
|
@@ -429,54 +433,71 @@ async function storageCleanupPass(args) {
|
|
|
429
433
|
// via selectMany (db/queries/export-jobs.ts).
|
|
430
434
|
const candidates = await selectExportJobsForStorageCleanup(db, EXPORT_JOB_STATUS.Done, EXPORT_JOB_STATUS.Failed);
|
|
431
435
|
const cleaned = [];
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
// see EXPORT_CLEANUP_BACKLOG_AGE_METRIC's r.metric() description.
|
|
436
|
+
// Candidates past their due-instant, keyed by that instant — used below to
|
|
437
|
+
// report how far cleanup has fallen behind if a candidate is still standing
|
|
438
|
+
// (delete threw, or the version-checked null-out lost a race) once the pass
|
|
439
|
+
// is done. Done jobs are due at expiresAt+grace; Failed jobs (orphaned ZIPs,
|
|
440
|
+
// no TTL) are due at completedAt ?? startedAt, i.e. from the first pass.
|
|
438
441
|
const overdueDoneCleanupAfterMs = new Map();
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
// durch (kein User-Pfad → sofort cleanup).
|
|
444
|
-
if (c.status === EXPORT_JOB_STATUS.Done) {
|
|
445
|
-
if (!c.expiresAt)
|
|
442
|
+
let passCompleted = false;
|
|
443
|
+
try {
|
|
444
|
+
for (const c of candidates) {
|
|
445
|
+
if (!c.downloadStorageKey)
|
|
446
446
|
continue;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
447
|
+
// Done jobs need the expiresAt+grace check. Failed jobs pass straight
|
|
448
|
+
// through (no user path, so clean up immediately).
|
|
449
|
+
if (c.status === EXPORT_JOB_STATUS.Done) {
|
|
450
|
+
if (!c.expiresAt)
|
|
451
|
+
continue;
|
|
452
|
+
// Count the candidate as overdue (lower bound, grace unknown) before the
|
|
453
|
+
// throwing profile lookup, so a failing pass still shows a backlog.
|
|
454
|
+
overdueDoneCleanupAfterMs.set(c.id, c.expiresAt.epochMilliseconds);
|
|
455
|
+
const profile = await resolveProfileForTenant({
|
|
456
|
+
db,
|
|
457
|
+
tenantId: c.requestedFromTenantId,
|
|
458
|
+
});
|
|
459
|
+
const cleanupAfter = c.expiresAt.epochMilliseconds +
|
|
460
|
+
profile.profile.userRights.exportStorageCleanupGraceHours * 60 * 60 * 1000;
|
|
461
|
+
if (now.epochMilliseconds < cleanupAfter) {
|
|
462
|
+
overdueDoneCleanupAfterMs.delete(c.id);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
overdueDoneCleanupAfterMs.set(c.id, cleanupAfter);
|
|
466
|
+
}
|
|
467
|
+
// Failed-job branch: no TTL check, clean up immediately.
|
|
468
|
+
else {
|
|
469
|
+
const failedAt = c.completedAt ?? c.startedAt;
|
|
470
|
+
if (failedAt)
|
|
471
|
+
overdueDoneCleanupAfterMs.set(c.id, failedAt.epochMilliseconds);
|
|
472
|
+
}
|
|
473
|
+
// Delete the storage file and null the DB column.
|
|
474
|
+
try {
|
|
475
|
+
const provider = await buildStorageProvider(c.requestedFromTenantId);
|
|
476
|
+
await provider.delete(c.downloadStorageKey);
|
|
477
|
+
}
|
|
478
|
+
catch {
|
|
479
|
+
// best-effort; if the storage delete fails, retry on the next pass
|
|
454
480
|
continue;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
catch {
|
|
464
|
-
// best-effort; wenn Storage-Delete failed, retry beim naechsten Pass
|
|
465
|
-
continue;
|
|
481
|
+
}
|
|
482
|
+
const result = await crud.update({
|
|
483
|
+
id: c.id,
|
|
484
|
+
version: c.version,
|
|
485
|
+
changes: { downloadStorageKey: null },
|
|
486
|
+
}, createSystemUser(c.requestedFromTenantId), systemTenantDb(db, c.requestedFromTenantId));
|
|
487
|
+
if (result.isSuccess)
|
|
488
|
+
cleaned.push(c.id);
|
|
466
489
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
cleaned.push(c.id);
|
|
490
|
+
passCompleted = true;
|
|
491
|
+
}
|
|
492
|
+
finally {
|
|
493
|
+
reportOldestOverdueAge(metrics, overdueDoneCleanupAfterMs, cleaned, now);
|
|
494
|
+
if (passCompleted)
|
|
495
|
+
reportCleanupLastRun(metrics, now);
|
|
474
496
|
}
|
|
475
|
-
reportOldestOverdueAge(metrics, overdueDoneCleanupAfterMs, cleaned, now);
|
|
476
497
|
return cleaned;
|
|
477
498
|
}
|
|
478
|
-
// Seconds since the longest-overdue
|
|
479
|
-
//
|
|
499
|
+
// Seconds since the longest-overdue bundle (Done: expiresAt+grace passed;
|
|
500
|
+
// Failed: completedAt ?? startedAt) should have been deleted but still isn't — 0 when the pass
|
|
480
501
|
// cleaned everything that was due, or nothing was due.
|
|
481
502
|
function oldestOverdueAgeSeconds(overdueDoneCleanupAfterMs, cleanedIds, now) {
|
|
482
503
|
const cleaned = new Set(cleanedIds);
|
|
@@ -505,6 +526,18 @@ function reportOldestOverdueAge(metrics, overdueDoneCleanupAfterMs, cleanedIds,
|
|
|
505
526
|
console.warn(`[user-data-rights:run-export-jobs] metrics.set(${EXPORT_CLEANUP_BACKLOG_AGE_METRIC}) failed err=${err instanceof Error ? err.message : String(err)}`);
|
|
506
527
|
}
|
|
507
528
|
}
|
|
529
|
+
function reportCleanupLastRun(metrics, now) {
|
|
530
|
+
// skip: no meter configured means there is nothing to report.
|
|
531
|
+
if (!metrics)
|
|
532
|
+
return;
|
|
533
|
+
try {
|
|
534
|
+
metrics.set(EXPORT_CLEANUP_LAST_RUN_TIMESTAMP_METRIC, now.epochMilliseconds / 1000);
|
|
535
|
+
}
|
|
536
|
+
catch (err) {
|
|
537
|
+
// biome-ignore lint/suspicious/noConsole: operator-visibility for observability-emit-failure
|
|
538
|
+
console.warn(`[user-data-rights:run-export-jobs] metrics.set(${EXPORT_CLEANUP_LAST_RUN_TIMESTAMP_METRIC}) failed err=${err instanceof Error ? err.message : String(err)}`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
508
541
|
// Wrapper: crud.update braucht TenantDb. ExportJob ist tenant-agnostisch
|
|
509
542
|
// (1 Job pro userId), aber der event-store-Stream-Lookup erwartet einen
|
|
510
543
|
// Tenant-Context. system-mode TenantDb bypassed den auto-tenant-filter
|
|
@@ -35,7 +35,7 @@ import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
|
35
35
|
import { configuredPiiSubjectKms, subjectIdToKey, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
36
36
|
import { createTenantDb, entityEventName, executeRawQuery, nullBlindIndexesForSubject, } from "@cosmicdrift/kumiko-framework/db";
|
|
37
37
|
import { EXT_USER_DATA, EXT_USER_DATA_ORDER, extensionUsageEscapeHatchReason, } from "@cosmicdrift/kumiko-framework/engine";
|
|
38
|
-
import { createEscapeHatchReporter } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
38
|
+
import { createEscapeHatchReporter, UNATTRIBUTED_ACTOR, } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
39
39
|
import { purgeSearchDocumentsForSubject, } from "@cosmicdrift/kumiko-framework/search";
|
|
40
40
|
import { resolveRetentionPolicyForTenant, resolveTenantRetentionPreset, } from "../data-retention/index.js";
|
|
41
41
|
import { decryptStoredPii, runInSubTransaction } from "../shared/index.js";
|
|
@@ -47,7 +47,7 @@ function buildHookDb(db, tenantId, entry, args) {
|
|
|
47
47
|
const report = createEscapeHatchReporter({
|
|
48
48
|
handler: `${EXT_USER_DATA}:${entry.entityName}`,
|
|
49
49
|
tenantId,
|
|
50
|
-
actor: args.actor ??
|
|
50
|
+
actor: args.actor ?? UNATTRIBUTED_ACTOR,
|
|
51
51
|
sink: args.escapeHatchAuditSink,
|
|
52
52
|
});
|
|
53
53
|
return createTenantDb(db, tenantId, "tenant", undefined, undefined, undefined, {
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
23
23
|
import { configuredPiiSubjectKms, decryptPiiFieldValues, isPiiCiphertext, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
24
24
|
import { collectEncryptedFieldNames, configuredEntityFieldEncryption, createTenantDb, decryptEntityFieldValues, } from "@cosmicdrift/kumiko-framework/db";
|
|
25
|
-
import { EXT_USER_DATA, extensionUsageEscapeHatchReason, } from "@cosmicdrift/kumiko-framework/engine";
|
|
26
|
-
import { createEscapeHatchReporter } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
25
|
+
import { EXT_USER_DATA, extensionUsageEscapeHatchReason, maskWriteOnlyFields, } from "@cosmicdrift/kumiko-framework/engine";
|
|
26
|
+
import { createEscapeHatchReporter, UNATTRIBUTED_ACTOR, } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
27
27
|
import { tenantMembershipsTable } from "../tenant/index.js";
|
|
28
28
|
import { buildFileRefZipPath } from "./zip-path.js";
|
|
29
29
|
function buildHookDb(db, tenantId, entry, args) {
|
|
30
30
|
const report = createEscapeHatchReporter({
|
|
31
31
|
handler: `${EXT_USER_DATA}:${entry.entityName}`,
|
|
32
32
|
tenantId,
|
|
33
|
-
actor: args.actor ??
|
|
33
|
+
actor: args.actor ?? UNATTRIBUTED_ACTOR,
|
|
34
34
|
sink: args.escapeHatchAuditSink,
|
|
35
35
|
});
|
|
36
36
|
return createTenantDb(db, tenantId, "tenant", undefined, undefined, undefined, {
|
|
@@ -214,7 +214,11 @@ async function decryptSnippetFields(registry, hookEntityName, snippet) {
|
|
|
214
214
|
const entity = registry.getEntity(snippet.entity) ?? registry.getEntity(hookEntityName);
|
|
215
215
|
const encryptedFields = entity ? collectEncryptedFieldNames(entity) : new Set();
|
|
216
216
|
const kms = configuredPiiSubjectKms();
|
|
217
|
-
const
|
|
217
|
+
const decryptedRows = await decryptRecords(snippet.rows, encryptedFields, kms);
|
|
218
|
+
// Decrypting would otherwise hand writeOnly secrets out as plaintext.
|
|
219
|
+
const rows = entity
|
|
220
|
+
? decryptedRows.map((row) => maskWriteOnlyFields(entity, row))
|
|
221
|
+
: decryptedRows;
|
|
218
222
|
if (!snippet.fileRefs || snippet.fileRefs.length === 0) {
|
|
219
223
|
return { ...snippet, rows };
|
|
220
224
|
}
|
|
@@ -9,6 +9,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
9
9
|
readonly filterable?: boolean;
|
|
10
10
|
readonly encrypted?: boolean;
|
|
11
11
|
readonly sensitive?: boolean;
|
|
12
|
+
readonly writeOnly?: boolean;
|
|
12
13
|
readonly readAsInstruction?: boolean;
|
|
13
14
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
14
15
|
readonly default?: string;
|
|
@@ -29,6 +30,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
29
30
|
readonly filterable?: boolean;
|
|
30
31
|
readonly encrypted?: boolean;
|
|
31
32
|
readonly sensitive?: boolean;
|
|
33
|
+
readonly writeOnly?: boolean;
|
|
32
34
|
readonly readAsInstruction?: boolean;
|
|
33
35
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
34
36
|
readonly default?: string;
|
|
@@ -49,6 +51,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
49
51
|
readonly filterable?: boolean;
|
|
50
52
|
readonly encrypted?: boolean;
|
|
51
53
|
readonly sensitive?: boolean;
|
|
54
|
+
readonly writeOnly?: boolean;
|
|
52
55
|
readonly readAsInstruction?: boolean;
|
|
53
56
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
54
57
|
readonly default?: string;
|
|
@@ -69,6 +72,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
69
72
|
readonly filterable?: boolean;
|
|
70
73
|
readonly encrypted?: boolean;
|
|
71
74
|
readonly sensitive?: boolean;
|
|
75
|
+
readonly writeOnly?: boolean;
|
|
72
76
|
readonly readAsInstruction?: boolean;
|
|
73
77
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
74
78
|
readonly default?: string;
|
|
@@ -89,6 +93,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
89
93
|
readonly filterable?: boolean;
|
|
90
94
|
readonly encrypted?: boolean;
|
|
91
95
|
readonly sensitive?: boolean;
|
|
96
|
+
readonly writeOnly?: boolean;
|
|
92
97
|
readonly readAsInstruction?: boolean;
|
|
93
98
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
94
99
|
readonly default?: string;
|
|
@@ -109,6 +114,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
109
114
|
readonly filterable?: boolean;
|
|
110
115
|
readonly encrypted?: boolean;
|
|
111
116
|
readonly sensitive?: boolean;
|
|
117
|
+
readonly writeOnly?: boolean;
|
|
112
118
|
readonly readAsInstruction?: boolean;
|
|
113
119
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
114
120
|
readonly default?: string;
|
|
@@ -129,6 +135,7 @@ export declare const downloadAttemptEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
129
135
|
readonly filterable?: boolean;
|
|
130
136
|
readonly encrypted?: boolean;
|
|
131
137
|
readonly sensitive?: boolean;
|
|
138
|
+
readonly writeOnly?: boolean;
|
|
132
139
|
readonly readAsInstruction?: boolean;
|
|
133
140
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
134
141
|
readonly default?: string;
|
|
@@ -166,6 +173,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
166
173
|
readonly filterable?: boolean;
|
|
167
174
|
readonly encrypted?: boolean;
|
|
168
175
|
readonly sensitive?: boolean;
|
|
176
|
+
readonly writeOnly?: boolean;
|
|
169
177
|
readonly readAsInstruction?: boolean;
|
|
170
178
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
171
179
|
readonly default?: string;
|
|
@@ -186,6 +194,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
186
194
|
readonly filterable?: boolean;
|
|
187
195
|
readonly encrypted?: boolean;
|
|
188
196
|
readonly sensitive?: boolean;
|
|
197
|
+
readonly writeOnly?: boolean;
|
|
189
198
|
readonly readAsInstruction?: boolean;
|
|
190
199
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
191
200
|
readonly default?: string;
|
|
@@ -206,6 +215,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
206
215
|
readonly filterable?: boolean;
|
|
207
216
|
readonly encrypted?: boolean;
|
|
208
217
|
readonly sensitive?: boolean;
|
|
218
|
+
readonly writeOnly?: boolean;
|
|
209
219
|
readonly readAsInstruction?: boolean;
|
|
210
220
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
211
221
|
readonly default?: string;
|
|
@@ -226,6 +236,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
226
236
|
readonly filterable?: boolean;
|
|
227
237
|
readonly encrypted?: boolean;
|
|
228
238
|
readonly sensitive?: boolean;
|
|
239
|
+
readonly writeOnly?: boolean;
|
|
229
240
|
readonly readAsInstruction?: boolean;
|
|
230
241
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
231
242
|
readonly default?: string;
|
|
@@ -246,6 +257,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
246
257
|
readonly filterable?: boolean;
|
|
247
258
|
readonly encrypted?: boolean;
|
|
248
259
|
readonly sensitive?: boolean;
|
|
260
|
+
readonly writeOnly?: boolean;
|
|
249
261
|
readonly readAsInstruction?: boolean;
|
|
250
262
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
251
263
|
readonly default?: string;
|
|
@@ -266,6 +278,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
266
278
|
readonly filterable?: boolean;
|
|
267
279
|
readonly encrypted?: boolean;
|
|
268
280
|
readonly sensitive?: boolean;
|
|
281
|
+
readonly writeOnly?: boolean;
|
|
269
282
|
readonly readAsInstruction?: boolean;
|
|
270
283
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
271
284
|
readonly default?: string;
|
|
@@ -286,6 +299,7 @@ export declare const downloadAttemptsTable: import("@cosmicdrift/kumiko-framewor
|
|
|
286
299
|
readonly filterable?: boolean;
|
|
287
300
|
readonly encrypted?: boolean;
|
|
288
301
|
readonly sensitive?: boolean;
|
|
302
|
+
readonly writeOnly?: boolean;
|
|
289
303
|
readonly readAsInstruction?: boolean;
|
|
290
304
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
291
305
|
readonly default?: string;
|
|
@@ -9,6 +9,7 @@ export declare const exportDownloadTokenEntity: import("@cosmicdrift/kumiko-type
|
|
|
9
9
|
readonly filterable?: boolean;
|
|
10
10
|
readonly encrypted?: boolean;
|
|
11
11
|
readonly sensitive?: boolean;
|
|
12
|
+
readonly writeOnly?: boolean;
|
|
12
13
|
readonly readAsInstruction?: boolean;
|
|
13
14
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
14
15
|
readonly default?: string;
|
|
@@ -29,6 +30,7 @@ export declare const exportDownloadTokenEntity: import("@cosmicdrift/kumiko-type
|
|
|
29
30
|
readonly filterable?: boolean;
|
|
30
31
|
readonly encrypted?: boolean;
|
|
31
32
|
readonly sensitive?: boolean;
|
|
33
|
+
readonly writeOnly?: boolean;
|
|
32
34
|
readonly readAsInstruction?: boolean;
|
|
33
35
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
34
36
|
readonly default?: string;
|
|
@@ -106,6 +108,7 @@ export declare const exportDownloadTokenEntity: import("@cosmicdrift/kumiko-type
|
|
|
106
108
|
readonly filterable?: boolean;
|
|
107
109
|
readonly encrypted?: boolean;
|
|
108
110
|
readonly sensitive?: boolean;
|
|
111
|
+
readonly writeOnly?: boolean;
|
|
109
112
|
readonly readAsInstruction?: boolean;
|
|
110
113
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
111
114
|
readonly default?: string;
|
|
@@ -126,6 +129,7 @@ export declare const exportDownloadTokenEntity: import("@cosmicdrift/kumiko-type
|
|
|
126
129
|
readonly filterable?: boolean;
|
|
127
130
|
readonly encrypted?: boolean;
|
|
128
131
|
readonly sensitive?: boolean;
|
|
132
|
+
readonly writeOnly?: boolean;
|
|
129
133
|
readonly readAsInstruction?: boolean;
|
|
130
134
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
131
135
|
readonly default?: string;
|
|
@@ -148,6 +152,7 @@ export declare const exportDownloadTokensTable: import("@cosmicdrift/kumiko-fram
|
|
|
148
152
|
readonly filterable?: boolean;
|
|
149
153
|
readonly encrypted?: boolean;
|
|
150
154
|
readonly sensitive?: boolean;
|
|
155
|
+
readonly writeOnly?: boolean;
|
|
151
156
|
readonly readAsInstruction?: boolean;
|
|
152
157
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
153
158
|
readonly default?: string;
|
|
@@ -168,6 +173,7 @@ export declare const exportDownloadTokensTable: import("@cosmicdrift/kumiko-fram
|
|
|
168
173
|
readonly filterable?: boolean;
|
|
169
174
|
readonly encrypted?: boolean;
|
|
170
175
|
readonly sensitive?: boolean;
|
|
176
|
+
readonly writeOnly?: boolean;
|
|
171
177
|
readonly readAsInstruction?: boolean;
|
|
172
178
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
173
179
|
readonly default?: string;
|
|
@@ -245,6 +251,7 @@ export declare const exportDownloadTokensTable: import("@cosmicdrift/kumiko-fram
|
|
|
245
251
|
readonly filterable?: boolean;
|
|
246
252
|
readonly encrypted?: boolean;
|
|
247
253
|
readonly sensitive?: boolean;
|
|
254
|
+
readonly writeOnly?: boolean;
|
|
248
255
|
readonly readAsInstruction?: boolean;
|
|
249
256
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
250
257
|
readonly default?: string;
|
|
@@ -265,6 +272,7 @@ export declare const exportDownloadTokensTable: import("@cosmicdrift/kumiko-fram
|
|
|
265
272
|
readonly filterable?: boolean;
|
|
266
273
|
readonly encrypted?: boolean;
|
|
267
274
|
readonly sensitive?: boolean;
|
|
275
|
+
readonly writeOnly?: boolean;
|
|
268
276
|
readonly readAsInstruction?: boolean;
|
|
269
277
|
readonly format?: "email" | "url" | "phone" | "password";
|
|
270
278
|
readonly default?: string;
|