@aphexcms/cms-core 9.8.1 → 9.10.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/api/organizations.d.ts +2 -1
- package/dist/api/organizations.d.ts.map +1 -1
- package/dist/api/organizations.js +2 -1
- package/dist/api/schemas/documents.d.ts +1 -0
- package/dist/api/schemas/documents.d.ts.map +1 -1
- package/dist/api/schemas/documents.js +1 -0
- package/dist/api/schemas/jobs.d.ts +15 -0
- package/dist/api/schemas/jobs.d.ts.map +1 -0
- package/dist/api/schemas/jobs.js +17 -0
- package/dist/api/schemas/user.d.ts.map +1 -1
- package/dist/api/schemas/user.js +6 -2
- package/dist/auth/account-deletion.d.ts +35 -0
- package/dist/auth/account-deletion.d.ts.map +1 -0
- package/dist/auth/account-deletion.js +65 -0
- package/dist/auth/bootstrap.d.ts +104 -0
- package/dist/auth/bootstrap.d.ts.map +1 -0
- package/dist/auth/bootstrap.js +164 -0
- package/dist/auth/instance-state.d.ts +13 -0
- package/dist/auth/instance-state.d.ts.map +1 -0
- package/dist/auth/instance-state.js +30 -0
- package/dist/auth/invitation-status.d.ts +25 -0
- package/dist/auth/invitation-status.d.ts.map +1 -0
- package/dist/auth/invitation-status.js +41 -0
- package/dist/auth/sign-up-policy.d.ts +62 -0
- package/dist/auth/sign-up-policy.d.ts.map +1 -0
- package/dist/auth/sign-up-policy.js +120 -0
- package/dist/components/AdminApp.svelte +83 -6
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/ActivityView.svelte +263 -13
- package/dist/components/admin/ActivityView.svelte.d.ts +10 -1
- package/dist/components/admin/ActivityView.svelte.d.ts.map +1 -1
- package/dist/db/interfaces/document.d.ts +9 -0
- package/dist/db/interfaces/document.d.ts.map +1 -1
- package/dist/db/interfaces/events.d.ts +29 -2
- package/dist/db/interfaces/events.d.ts.map +1 -1
- package/dist/db/interfaces/index.d.ts +1 -0
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/index.js +1 -0
- package/dist/db/interfaces/instance.d.ts +29 -0
- package/dist/db/interfaces/instance.d.ts.map +1 -1
- package/dist/db/interfaces/instance.js +8 -1
- package/dist/events/built-in-consumers.d.ts +20 -0
- package/dist/events/built-in-consumers.d.ts.map +1 -0
- package/dist/events/built-in-consumers.js +49 -0
- package/dist/events/catalog.d.ts +16 -0
- package/dist/events/catalog.d.ts.map +1 -1
- package/dist/events/catalog.js +17 -0
- package/dist/events/consumer.d.ts +14 -0
- package/dist/events/consumer.d.ts.map +1 -1
- package/dist/events/consumer.js +1 -0
- package/dist/events/emit.d.ts +23 -0
- package/dist/events/emit.d.ts.map +1 -1
- package/dist/events/emit.js +32 -1
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +2 -0
- package/dist/field-validation/utils.d.ts +27 -4
- package/dist/field-validation/utils.d.ts.map +1 -1
- package/dist/field-validation/utils.js +78 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/jobs/run-batch.d.ts +7 -1
- package/dist/jobs/run-batch.d.ts.map +1 -1
- package/dist/jobs/run-batch.js +3 -1
- package/dist/lib/api/organizations.d.ts +2 -1
- package/dist/lib/api/organizations.d.ts.map +1 -1
- package/dist/lib/api/organizations.js +2 -1
- package/dist/lib/api/organizations.js.map +1 -1
- package/dist/lib/api/schemas/api-keys.d.ts +4 -4
- package/dist/lib/api/schemas/documents.d.ts +1 -0
- package/dist/lib/api/schemas/documents.d.ts.map +1 -1
- package/dist/lib/api/schemas/documents.js +1 -0
- package/dist/lib/api/schemas/documents.js.map +1 -1
- package/dist/lib/api/schemas/jobs.d.ts +15 -0
- package/dist/lib/api/schemas/jobs.d.ts.map +1 -0
- package/dist/lib/api/schemas/jobs.js +18 -0
- package/dist/lib/api/schemas/jobs.js.map +1 -0
- package/dist/lib/api/schemas/user.d.ts.map +1 -1
- package/dist/lib/api/schemas/user.js +6 -2
- package/dist/lib/api/schemas/user.js.map +1 -1
- package/dist/lib/auth/account-deletion.d.ts +35 -0
- package/dist/lib/auth/account-deletion.d.ts.map +1 -0
- package/dist/lib/auth/account-deletion.js +66 -0
- package/dist/lib/auth/account-deletion.js.map +1 -0
- package/dist/lib/auth/bootstrap.d.ts +104 -0
- package/dist/lib/auth/bootstrap.d.ts.map +1 -0
- package/dist/lib/auth/bootstrap.js +165 -0
- package/dist/lib/auth/bootstrap.js.map +1 -0
- package/dist/lib/auth/instance-state.d.ts +13 -0
- package/dist/lib/auth/instance-state.d.ts.map +1 -0
- package/dist/lib/auth/instance-state.js +31 -0
- package/dist/lib/auth/instance-state.js.map +1 -0
- package/dist/lib/auth/invitation-status.d.ts +25 -0
- package/dist/lib/auth/invitation-status.d.ts.map +1 -0
- package/dist/lib/auth/invitation-status.js +42 -0
- package/dist/lib/auth/invitation-status.js.map +1 -0
- package/dist/lib/auth/sign-up-policy.d.ts +62 -0
- package/dist/lib/auth/sign-up-policy.d.ts.map +1 -0
- package/dist/lib/auth/sign-up-policy.js +121 -0
- package/dist/lib/auth/sign-up-policy.js.map +1 -0
- package/dist/lib/db/interfaces/document.d.ts +9 -0
- package/dist/lib/db/interfaces/document.d.ts.map +1 -1
- package/dist/lib/db/interfaces/events.d.ts +29 -2
- package/dist/lib/db/interfaces/events.d.ts.map +1 -1
- package/dist/lib/db/interfaces/index.d.ts +1 -0
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/index.js +1 -0
- package/dist/lib/db/interfaces/index.js.map +1 -1
- package/dist/lib/db/interfaces/instance.d.ts +29 -0
- package/dist/lib/db/interfaces/instance.d.ts.map +1 -1
- package/dist/lib/db/interfaces/instance.js +8 -1
- package/dist/lib/db/interfaces/instance.js.map +1 -1
- package/dist/lib/events/built-in-consumers.d.ts +20 -0
- package/dist/lib/events/built-in-consumers.d.ts.map +1 -0
- package/dist/lib/events/built-in-consumers.js +50 -0
- package/dist/lib/events/built-in-consumers.js.map +1 -0
- package/dist/lib/events/catalog.d.ts +16 -0
- package/dist/lib/events/catalog.d.ts.map +1 -1
- package/dist/lib/events/catalog.js +17 -0
- package/dist/lib/events/catalog.js.map +1 -1
- package/dist/lib/events/consumer.d.ts +14 -0
- package/dist/lib/events/consumer.d.ts.map +1 -1
- package/dist/lib/events/consumer.js +1 -0
- package/dist/lib/events/consumer.js.map +1 -1
- package/dist/lib/events/emit.d.ts +23 -0
- package/dist/lib/events/emit.d.ts.map +1 -1
- package/dist/lib/events/emit.js +32 -1
- package/dist/lib/events/emit.js.map +1 -1
- package/dist/lib/events/index.d.ts +2 -0
- package/dist/lib/events/index.d.ts.map +1 -1
- package/dist/lib/events/index.js +2 -0
- package/dist/lib/events/index.js.map +1 -1
- package/dist/lib/field-validation/utils.d.ts +27 -4
- package/dist/lib/field-validation/utils.d.ts.map +1 -1
- package/dist/lib/field-validation/utils.js +78 -10
- package/dist/lib/field-validation/utils.js.map +1 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/jobs/run-batch.d.ts +7 -1
- package/dist/lib/jobs/run-batch.d.ts.map +1 -1
- package/dist/lib/jobs/run-batch.js +3 -1
- package/dist/lib/jobs/run-batch.js.map +1 -1
- package/dist/lib/local-api/collection-api.d.ts +48 -1
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +110 -11
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/local-api/index.d.ts +1 -1
- package/dist/lib/local-api/index.d.ts.map +1 -1
- package/dist/lib/local-api/index.js +1 -1
- package/dist/lib/local-api/index.js.map +1 -1
- package/dist/lib/plugins/resolver.d.ts.map +1 -1
- package/dist/lib/plugins/resolver.js +7 -1
- package/dist/lib/plugins/resolver.js.map +1 -1
- package/dist/lib/schema-utils/utils.d.ts +31 -1
- package/dist/lib/schema-utils/utils.d.ts.map +1 -1
- package/dist/lib/schema-utils/utils.js +68 -0
- package/dist/lib/schema-utils/utils.js.map +1 -1
- package/dist/lib/server/api/rate-limit.d.ts +38 -0
- package/dist/lib/server/api/rate-limit.d.ts.map +1 -0
- package/dist/lib/server/api/rate-limit.js +71 -0
- package/dist/lib/server/api/rate-limit.js.map +1 -0
- package/dist/lib/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.js +10 -1
- package/dist/lib/server/api/routes/documents-by-id.js.map +1 -1
- package/dist/lib/server/api/routes/documents-publish.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-publish.js +10 -0
- package/dist/lib/server/api/routes/documents-publish.js.map +1 -1
- package/dist/lib/server/api/routes/documents.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents.js +11 -0
- package/dist/lib/server/api/routes/documents.js.map +1 -1
- package/dist/lib/server/api/routes/jobs.d.ts.map +1 -1
- package/dist/lib/server/api/routes/jobs.js +174 -20
- package/dist/lib/server/api/routes/jobs.js.map +1 -1
- package/dist/lib/server/api/routes/organizations-by-id.d.ts.map +1 -1
- package/dist/lib/server/api/routes/organizations-by-id.js +61 -3
- package/dist/lib/server/api/routes/organizations-by-id.js.map +1 -1
- package/dist/lib/server/api/routes/organizations-invitations.d.ts.map +1 -1
- package/dist/lib/server/api/routes/organizations-invitations.js +31 -2
- package/dist/lib/server/api/routes/organizations-invitations.js.map +1 -1
- package/dist/lib/server/api/routes/resolve-organization-names.d.ts +17 -0
- package/dist/lib/server/api/routes/resolve-organization-names.d.ts.map +1 -0
- package/dist/lib/server/api/routes/resolve-organization-names.js +26 -0
- package/dist/lib/server/api/routes/resolve-organization-names.js.map +1 -0
- package/dist/lib/server/api/routes/user.d.ts +0 -8
- package/dist/lib/server/api/routes/user.d.ts.map +1 -1
- package/dist/lib/server/api/routes/user.js +144 -0
- package/dist/lib/server/api/routes/user.js.map +1 -1
- package/dist/lib/server/index.d.ts +6 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +9 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/type-gen.d.ts.map +1 -1
- package/dist/lib/type-gen.js +11 -5
- package/dist/lib/type-gen.js.map +1 -1
- package/dist/lib/types/capabilities.d.ts +14 -0
- package/dist/lib/types/capabilities.d.ts.map +1 -1
- package/dist/lib/types/capabilities.js +37 -18
- package/dist/lib/types/capabilities.js.map +1 -1
- package/dist/lib/types/events.d.ts +27 -4
- package/dist/lib/types/events.d.ts.map +1 -1
- package/dist/lib/types/filters.d.ts +31 -0
- package/dist/lib/types/filters.d.ts.map +1 -1
- package/dist/lib/types/schemas.d.ts +14 -0
- package/dist/lib/types/schemas.d.ts.map +1 -1
- package/dist/lib/utils/fetch-remote-file.d.ts.map +1 -1
- package/dist/lib/utils/fetch-remote-file.js +32 -3
- package/dist/lib/utils/fetch-remote-file.js.map +1 -1
- package/dist/local-api/collection-api.d.ts +48 -1
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +110 -11
- package/dist/local-api/index.d.ts +1 -1
- package/dist/local-api/index.d.ts.map +1 -1
- package/dist/local-api/index.js +1 -1
- package/dist/plugins/resolver.d.ts.map +1 -1
- package/dist/plugins/resolver.js +7 -1
- package/dist/schema-utils/utils.d.ts +31 -1
- package/dist/schema-utils/utils.d.ts.map +1 -1
- package/dist/schema-utils/utils.js +68 -0
- package/dist/server/api/rate-limit.d.ts +38 -0
- package/dist/server/api/rate-limit.d.ts.map +1 -0
- package/dist/server/api/rate-limit.js +70 -0
- package/dist/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/server/api/routes/documents-by-id.js +10 -1
- package/dist/server/api/routes/documents-publish.d.ts.map +1 -1
- package/dist/server/api/routes/documents-publish.js +10 -0
- package/dist/server/api/routes/documents.d.ts.map +1 -1
- package/dist/server/api/routes/documents.js +11 -0
- package/dist/server/api/routes/jobs.d.ts.map +1 -1
- package/dist/server/api/routes/jobs.js +174 -20
- package/dist/server/api/routes/organizations-by-id.d.ts.map +1 -1
- package/dist/server/api/routes/organizations-by-id.js +61 -3
- package/dist/server/api/routes/organizations-invitations.d.ts.map +1 -1
- package/dist/server/api/routes/organizations-invitations.js +31 -2
- package/dist/server/api/routes/resolve-organization-names.d.ts +17 -0
- package/dist/server/api/routes/resolve-organization-names.d.ts.map +1 -0
- package/dist/server/api/routes/resolve-organization-names.js +25 -0
- package/dist/server/api/routes/user.d.ts +0 -8
- package/dist/server/api/routes/user.d.ts.map +1 -1
- package/dist/server/api/routes/user.js +144 -0
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +9 -1
- package/dist/type-gen.d.ts.map +1 -1
- package/dist/type-gen.js +11 -5
- package/dist/types/capabilities.d.ts +14 -0
- package/dist/types/capabilities.d.ts.map +1 -1
- package/dist/types/capabilities.js +37 -18
- package/dist/types/events.d.ts +27 -4
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/filters.d.ts +31 -0
- package/dist/types/filters.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +14 -0
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/utils/fetch-remote-file.d.ts.map +1 -1
- package/dist/utils/fetch-remote-file.js +32 -3
- package/package.json +6 -6
|
@@ -7,25 +7,58 @@
|
|
|
7
7
|
import { onMount } from 'svelte';
|
|
8
8
|
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
9
9
|
import { Badge } from '@aphexcms/ui/shadcn/badge';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
RefreshCw,
|
|
12
|
+
CalendarClock,
|
|
13
|
+
Radio,
|
|
14
|
+
Sparkles,
|
|
15
|
+
Undo2,
|
|
16
|
+
ChevronDown,
|
|
17
|
+
RotateCcw,
|
|
18
|
+
Ban,
|
|
19
|
+
TriangleAlert
|
|
20
|
+
} from '@lucide/svelte';
|
|
11
21
|
import { toast } from 'svelte-sonner';
|
|
12
22
|
import { apiClient } from '../../api/client';
|
|
13
|
-
import type { Job, DomainEvent, JobStatus } from '../../types/events';
|
|
23
|
+
import type { Job, DomainEvent, JobStatus, OutboxHealth } from '../../types/events';
|
|
14
24
|
import type {
|
|
15
25
|
AgentChangeSet,
|
|
16
26
|
AgentChangeSetWithOperations,
|
|
17
27
|
AgentChangeSetStatus
|
|
18
28
|
} from '../../types/agent-change-sets';
|
|
19
29
|
|
|
30
|
+
type Props = {
|
|
31
|
+
/**
|
|
32
|
+
* May the viewer retry/cancel jobs? `org.settings` — see `requireJobControl` in the
|
|
33
|
+
* route. Gating here only hides buttons; the server is what enforces it.
|
|
34
|
+
*/
|
|
35
|
+
canControlJobs?: boolean;
|
|
36
|
+
/** Super admins can widen jobs/events past their active organization (`?scope=all`). */
|
|
37
|
+
isSuperAdmin?: boolean;
|
|
38
|
+
};
|
|
39
|
+
let { canControlJobs = false, isSuperAdmin = false }: Props = $props();
|
|
40
|
+
|
|
20
41
|
// The server resolves `createdBy` (a raw user id) to a display name — see
|
|
21
42
|
// `resolve-created-by.ts`, shared by GET /api/events and GET /api/agent/change-sets.
|
|
22
43
|
type WithCreatedByName<T> = T & { createdByName: string | null };
|
|
44
|
+
// …and `organizationId` to an org name, but only in the instance-wide view, where rows
|
|
45
|
+
// from several tenants share a table. Absent (not null) in the org-scoped view.
|
|
46
|
+
type WithOrganizationName<T> = T & { organizationName?: string | null };
|
|
23
47
|
|
|
24
48
|
type Tab = 'jobs' | 'events' | 'agent';
|
|
25
49
|
let tab = $state<Tab>('jobs');
|
|
26
50
|
|
|
27
|
-
|
|
28
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Whose history is on screen. `all` is a super-admin-only widening: the queue is
|
|
53
|
+
* instance-wide (one worker claims across every org), so a failure in a tenant you
|
|
54
|
+
* aren't currently switched into is otherwise invisible.
|
|
55
|
+
*/
|
|
56
|
+
let scope = $state<'organization' | 'all'>('organization');
|
|
57
|
+
|
|
58
|
+
let jobs = $state<WithOrganizationName<Job>[]>([]);
|
|
59
|
+
let events = $state<WithOrganizationName<WithCreatedByName<DomainEvent>>[]>([]);
|
|
60
|
+
let health = $state<OutboxHealth | null>(null);
|
|
61
|
+
let actingJobId = $state<string | null>(null);
|
|
29
62
|
let changeSets = $state<WithCreatedByName<AgentChangeSetWithOperations>[]>([]);
|
|
30
63
|
let loading = $state(false);
|
|
31
64
|
let error = $state<string | null>(null);
|
|
@@ -89,24 +122,86 @@
|
|
|
89
122
|
return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();
|
|
90
123
|
}
|
|
91
124
|
|
|
125
|
+
/** "3m", "2h", "4d" — coarse on purpose; this is a staleness signal, not a stopwatch. */
|
|
126
|
+
function age(d: string | Date): string {
|
|
127
|
+
const ms = Date.now() - new Date(d).getTime();
|
|
128
|
+
if (ms < 60_000) return `${Math.max(0, Math.round(ms / 1000))}s`;
|
|
129
|
+
if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;
|
|
130
|
+
if (ms < 86_400_000) return `${Math.round(ms / 3_600_000)}h`;
|
|
131
|
+
return `${Math.round(ms / 86_400_000)}d`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// A backlog older than this means the relay has stopped, not that it's busy. The
|
|
135
|
+
// self-hosted worker polls every 5s by default and platform cron runs at most once a
|
|
136
|
+
// minute, so a minute is the shortest gap that can't be explained by normal cadence.
|
|
137
|
+
const RELAY_STALE_MS = 60_000;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The backlog, pre-chewed into exactly what the banner renders — or null when there's
|
|
141
|
+
* nothing to say. Deriving the whole object (rather than a `stalled` flag beside the raw
|
|
142
|
+
* `health`) is what lets the markup read `oldestAge` without re-proving that
|
|
143
|
+
* `oldestPendingAt` is non-null: `pending > 0` implies a row exists, but only this
|
|
144
|
+
* narrowing tells the compiler so.
|
|
145
|
+
*/
|
|
146
|
+
const relayBacklog = $derived.by(() => {
|
|
147
|
+
const oldest = health?.oldestPendingAt;
|
|
148
|
+
if (!health || health.pending === 0 || !oldest) return null;
|
|
149
|
+
return {
|
|
150
|
+
pending: health.pending,
|
|
151
|
+
oldestAge: age(oldest),
|
|
152
|
+
stalled: Date.now() - new Date(oldest).getTime() > RELAY_STALE_MS
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A job whose lease has run out but which is still marked `leased` — the worker holding
|
|
158
|
+
* it died mid-run. It isn't lost (the next `claimDueJobs` reclaims expired leases), but
|
|
159
|
+
* it looks identical to healthy in-flight work without this.
|
|
160
|
+
*/
|
|
161
|
+
function leaseExpired(job: Job): boolean {
|
|
162
|
+
return (
|
|
163
|
+
job.status === 'leased' && !!job.leaseExpiresAt && new Date(job.leaseExpiresAt) < new Date()
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Requeue puts a dead letter back with a fresh attempt budget; cancel retires it. */
|
|
168
|
+
const canRetry = (job: Job) => job.status === 'failed' || job.status === 'cancelled';
|
|
169
|
+
const canCancel = (job: Job) => job.status === 'pending' || job.status === 'failed';
|
|
170
|
+
|
|
171
|
+
/** Only send `scope` when it's actually widened — keeps the default request unchanged. */
|
|
172
|
+
function scopeParam(): Record<string, string> {
|
|
173
|
+
return scope === 'all' ? { scope: 'all' } : {};
|
|
174
|
+
}
|
|
175
|
+
|
|
92
176
|
async function load() {
|
|
93
177
|
loading = true;
|
|
94
178
|
error = null;
|
|
95
179
|
try {
|
|
96
180
|
if (tab === 'jobs') {
|
|
97
|
-
const params: Record<string, string> = { limit: '100' };
|
|
181
|
+
const params: Record<string, string> = { limit: '100', ...scopeParam() };
|
|
98
182
|
if (statusFilter !== 'all') params.status = statusFilter;
|
|
99
|
-
|
|
183
|
+
// Health rides along with the list: it's the context for everything below it,
|
|
184
|
+
// and a separate refresh button for one number would be its own small trap.
|
|
185
|
+
const [res, healthRes] = await Promise.all([
|
|
186
|
+
apiClient.get<WithOrganizationName<Job>[]>('/jobs', params),
|
|
187
|
+
apiClient.get<OutboxHealth>('/jobs/health', scopeParam())
|
|
188
|
+
]);
|
|
100
189
|
if (res.success) {
|
|
101
190
|
jobs = res.data ?? [];
|
|
102
191
|
total = res.pagination?.total ?? jobs.length;
|
|
103
192
|
} else {
|
|
104
193
|
error = res.error ?? 'Failed to load jobs';
|
|
105
194
|
}
|
|
195
|
+
// A failed health read shouldn't blank the page — the list is still useful.
|
|
196
|
+
health = healthRes.success ? (healthRes.data ?? null) : null;
|
|
106
197
|
} else if (tab === 'events') {
|
|
107
|
-
const res = await apiClient.get<WithCreatedByName<DomainEvent
|
|
108
|
-
|
|
109
|
-
|
|
198
|
+
const res = await apiClient.get<WithOrganizationName<WithCreatedByName<DomainEvent>>[]>(
|
|
199
|
+
'/events',
|
|
200
|
+
{
|
|
201
|
+
limit: '100',
|
|
202
|
+
...scopeParam()
|
|
203
|
+
}
|
|
204
|
+
);
|
|
110
205
|
if (res.success) {
|
|
111
206
|
events = res.data ?? [];
|
|
112
207
|
total = res.pagination?.total ?? events.length;
|
|
@@ -138,6 +233,34 @@
|
|
|
138
233
|
load();
|
|
139
234
|
}
|
|
140
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Retry and cancel share everything but the verb and the past-tense confirmation, so they
|
|
238
|
+
* share a body. `organizationId` is always sent: in the instance-wide view the job may
|
|
239
|
+
* belong to a tenant the caller isn't switched into, and the server needs to be told which
|
|
240
|
+
* one (it rejects the mismatch unless you're a super admin).
|
|
241
|
+
*/
|
|
242
|
+
async function actOnJob(job: Job, action: 'retry' | 'cancel') {
|
|
243
|
+
if (actingJobId) return;
|
|
244
|
+
actingJobId = job.id;
|
|
245
|
+
try {
|
|
246
|
+
const res = await apiClient.post<Job>(`/jobs/${job.id}/${action}`, {
|
|
247
|
+
organizationId: job.organizationId
|
|
248
|
+
});
|
|
249
|
+
if (!res.success) {
|
|
250
|
+
toast.error(res.error ?? `Could not ${action} this job`);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
toast.success(
|
|
254
|
+
action === 'retry' ? 'Job requeued — it runs on the next tick.' : 'Job cancelled.'
|
|
255
|
+
);
|
|
256
|
+
await load();
|
|
257
|
+
} catch (err) {
|
|
258
|
+
toast.error(err instanceof Error ? err.message : `Could not ${action} this job`);
|
|
259
|
+
} finally {
|
|
260
|
+
actingJobId = null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
141
264
|
async function toggleExpand(changeSet: AgentChangeSet) {
|
|
142
265
|
if (expandedChangeSetId === changeSet.id) {
|
|
143
266
|
expandedChangeSetId = null;
|
|
@@ -196,6 +319,13 @@
|
|
|
196
319
|
if (tab === 'jobs') load();
|
|
197
320
|
});
|
|
198
321
|
|
|
322
|
+
// Scope applies to jobs and events alike, so this one reloads whichever is showing.
|
|
323
|
+
$effect(() => {
|
|
324
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- reactive dependency: re-run when scope changes
|
|
325
|
+
scope;
|
|
326
|
+
if (tab !== 'agent') load();
|
|
327
|
+
});
|
|
328
|
+
|
|
199
329
|
onMount(load);
|
|
200
330
|
</script>
|
|
201
331
|
|
|
@@ -207,9 +337,32 @@
|
|
|
207
337
|
Scheduled jobs, the domain-event log, and the AI assistant's audit trail.
|
|
208
338
|
</p>
|
|
209
339
|
</div>
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
340
|
+
<div class="flex items-center gap-2">
|
|
341
|
+
{#if isSuperAdmin && tab !== 'agent'}
|
|
342
|
+
<!-- The queue is instance-wide; this is the only view that can show it that way. -->
|
|
343
|
+
<div class="border-rule flex items-center rounded-md border p-0.5 text-xs">
|
|
344
|
+
<button
|
|
345
|
+
class="rounded px-2 py-1 transition-colors {scope === 'organization'
|
|
346
|
+
? 'bg-muted text-foreground'
|
|
347
|
+
: 'text-muted-foreground hover:text-foreground'}"
|
|
348
|
+
onclick={() => (scope = 'organization')}
|
|
349
|
+
>
|
|
350
|
+
This workspace
|
|
351
|
+
</button>
|
|
352
|
+
<button
|
|
353
|
+
class="rounded px-2 py-1 transition-colors {scope === 'all'
|
|
354
|
+
? 'bg-muted text-foreground'
|
|
355
|
+
: 'text-muted-foreground hover:text-foreground'}"
|
|
356
|
+
onclick={() => (scope = 'all')}
|
|
357
|
+
>
|
|
358
|
+
All workspaces
|
|
359
|
+
</button>
|
|
360
|
+
</div>
|
|
361
|
+
{/if}
|
|
362
|
+
<Button variant="outline" size="sm" onclick={load} disabled={loading} class="gap-1.5">
|
|
363
|
+
<RefreshCw class="h-3.5 w-3.5 {loading ? 'animate-spin' : ''}" /> Refresh
|
|
364
|
+
</Button>
|
|
365
|
+
</div>
|
|
213
366
|
</div>
|
|
214
367
|
|
|
215
368
|
<!-- Tabs -->
|
|
@@ -244,6 +397,43 @@
|
|
|
244
397
|
</div>
|
|
245
398
|
|
|
246
399
|
{#if tab === 'jobs'}
|
|
400
|
+
{#if relayBacklog}
|
|
401
|
+
<!--
|
|
402
|
+
The relay backlog. A count on its own is meaningless — a busy instance always has
|
|
403
|
+
rows in flight — so the age of the oldest is what decides the tone: past a minute,
|
|
404
|
+
nothing is draining the outbox and every consumer has silently stopped.
|
|
405
|
+
-->
|
|
406
|
+
<div
|
|
407
|
+
class="mb-3 flex items-start gap-2 rounded-md border p-3 text-sm {relayBacklog.stalled
|
|
408
|
+
? 'border-destructive/40 bg-destructive/10 text-destructive'
|
|
409
|
+
: 'border-rule text-muted-foreground'}"
|
|
410
|
+
>
|
|
411
|
+
{#if relayBacklog.stalled}
|
|
412
|
+
<TriangleAlert class="mt-0.5 h-4 w-4 shrink-0" />
|
|
413
|
+
{:else}
|
|
414
|
+
<Radio class="mt-0.5 h-4 w-4 shrink-0" />
|
|
415
|
+
{/if}
|
|
416
|
+
<div>
|
|
417
|
+
{#if relayBacklog.stalled}
|
|
418
|
+
<p class="font-medium">
|
|
419
|
+
The relay looks stopped — {relayBacklog.pending} event{relayBacklog.pending === 1
|
|
420
|
+
? ''
|
|
421
|
+
: 's'} waiting, oldest {relayBacklog.oldestAge} old.
|
|
422
|
+
</p>
|
|
423
|
+
<p class="mt-0.5 text-xs">
|
|
424
|
+
Nothing is reacting to events: scheduled publishes, erasure and plugin consumers are
|
|
425
|
+
all paused until a worker calls <code>POST /api/internal/workers/run</code> again.
|
|
426
|
+
</p>
|
|
427
|
+
{:else}
|
|
428
|
+
<p>
|
|
429
|
+
{relayBacklog.pending} event{relayBacklog.pending === 1 ? '' : 's'} waiting to fan out,
|
|
430
|
+
oldest {relayBacklog.oldestAge} old — the relay is keeping up.
|
|
431
|
+
</p>
|
|
432
|
+
{/if}
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
435
|
+
{/if}
|
|
436
|
+
|
|
247
437
|
<div class="mb-3 flex flex-wrap items-center gap-1.5">
|
|
248
438
|
{#each statuses as s (s)}
|
|
249
439
|
<button
|
|
@@ -276,19 +466,42 @@
|
|
|
276
466
|
<thead class="bg-muted/50 text-muted-foreground text-xs">
|
|
277
467
|
<tr>
|
|
278
468
|
<th class="px-3 py-2 text-left font-medium">Type</th>
|
|
469
|
+
{#if scope === 'all'}
|
|
470
|
+
<th class="px-3 py-2 text-left font-medium">Workspace</th>
|
|
471
|
+
{/if}
|
|
279
472
|
<th class="px-3 py-2 text-left font-medium">Status</th>
|
|
280
473
|
<th class="px-3 py-2 text-left font-medium">Run at</th>
|
|
281
474
|
<th class="px-3 py-2 text-left font-medium">Attempts</th>
|
|
282
475
|
<th class="px-3 py-2 text-left font-medium">Last error</th>
|
|
283
476
|
<th class="px-3 py-2 text-left font-medium">Created</th>
|
|
477
|
+
{#if canControlJobs}
|
|
478
|
+
<th class="px-3 py-2 text-right font-medium">Actions</th>
|
|
479
|
+
{/if}
|
|
284
480
|
</tr>
|
|
285
481
|
</thead>
|
|
286
482
|
<tbody>
|
|
287
483
|
{#each jobs as job (job.id)}
|
|
288
484
|
<tr class="border-rule border-t">
|
|
289
485
|
<td class="px-3 py-2 font-mono text-xs">{job.type}</td>
|
|
290
|
-
|
|
486
|
+
{#if scope === 'all'}
|
|
487
|
+
<td class="text-muted-foreground px-3 py-2 text-xs">
|
|
488
|
+
{job.organizationName ?? job.organizationId}
|
|
489
|
+
</td>
|
|
490
|
+
{/if}
|
|
491
|
+
<td class="px-3 py-2 whitespace-nowrap">
|
|
291
492
|
<Badge variant={statusVariant[job.status]} class="capitalize">{job.status}</Badge>
|
|
493
|
+
{#if leaseExpired(job)}
|
|
494
|
+
<!-- Still `leased` past its expiry: the worker that held it died. The next
|
|
495
|
+
claim reclaims it, so this is a diagnosis, not an action item. -->
|
|
496
|
+
<span
|
|
497
|
+
class="text-destructive ml-1.5 text-xs"
|
|
498
|
+
title="Lease expired {age(
|
|
499
|
+
job.leaseExpiresAt ?? new Date()
|
|
500
|
+
)} ago — the worker holding this job stopped. It will be reclaimed on the next tick."
|
|
501
|
+
>
|
|
502
|
+
stalled
|
|
503
|
+
</span>
|
|
504
|
+
{/if}
|
|
292
505
|
</td>
|
|
293
506
|
<td class="px-3 py-2 whitespace-nowrap">{fmt(job.runAt)}</td>
|
|
294
507
|
<td class="px-3 py-2">{job.attempts}/{job.maxAttempts}</td>
|
|
@@ -301,6 +514,35 @@
|
|
|
301
514
|
<td class="text-muted-foreground px-3 py-2 whitespace-nowrap"
|
|
302
515
|
>{fmt(job.createdAt)}</td
|
|
303
516
|
>
|
|
517
|
+
{#if canControlJobs}
|
|
518
|
+
<td class="px-3 py-2 text-right whitespace-nowrap">
|
|
519
|
+
{#if canRetry(job)}
|
|
520
|
+
<Button
|
|
521
|
+
variant="ghost"
|
|
522
|
+
size="sm"
|
|
523
|
+
class="h-7 gap-1 px-2 text-xs"
|
|
524
|
+
disabled={actingJobId !== null}
|
|
525
|
+
onclick={() => actOnJob(job, 'retry')}
|
|
526
|
+
>
|
|
527
|
+
<RotateCcw class="h-3 w-3" /> Retry
|
|
528
|
+
</Button>
|
|
529
|
+
{/if}
|
|
530
|
+
{#if canCancel(job)}
|
|
531
|
+
<Button
|
|
532
|
+
variant="ghost"
|
|
533
|
+
size="sm"
|
|
534
|
+
class="text-muted-foreground h-7 gap-1 px-2 text-xs"
|
|
535
|
+
disabled={actingJobId !== null}
|
|
536
|
+
onclick={() => actOnJob(job, 'cancel')}
|
|
537
|
+
>
|
|
538
|
+
<Ban class="h-3 w-3" /> Cancel
|
|
539
|
+
</Button>
|
|
540
|
+
{/if}
|
|
541
|
+
{#if !canRetry(job) && !canCancel(job)}
|
|
542
|
+
<span class="text-muted-foreground text-xs">—</span>
|
|
543
|
+
{/if}
|
|
544
|
+
</td>
|
|
545
|
+
{/if}
|
|
304
546
|
</tr>
|
|
305
547
|
{/each}
|
|
306
548
|
</tbody>
|
|
@@ -317,6 +559,9 @@
|
|
|
317
559
|
<thead class="bg-muted/50 text-muted-foreground text-xs">
|
|
318
560
|
<tr>
|
|
319
561
|
<th class="px-3 py-2 text-left font-medium">Type</th>
|
|
562
|
+
{#if scope === 'all'}
|
|
563
|
+
<th class="px-3 py-2 text-left font-medium">Workspace</th>
|
|
564
|
+
{/if}
|
|
320
565
|
<th class="px-3 py-2 text-left font-medium">Payload</th>
|
|
321
566
|
<th class="px-3 py-2 text-left font-medium">By</th>
|
|
322
567
|
<th class="px-3 py-2 text-left font-medium">When</th>
|
|
@@ -326,6 +571,11 @@
|
|
|
326
571
|
{#each events as event (event.id)}
|
|
327
572
|
<tr class="border-rule border-t">
|
|
328
573
|
<td class="px-3 py-2 font-mono text-xs">{event.type}</td>
|
|
574
|
+
{#if scope === 'all'}
|
|
575
|
+
<td class="text-muted-foreground px-3 py-2 text-xs">
|
|
576
|
+
{event.organizationName ?? event.organizationId}
|
|
577
|
+
</td>
|
|
578
|
+
{/if}
|
|
329
579
|
<td
|
|
330
580
|
class="text-muted-foreground max-w-[320px] truncate px-3 py-2 font-mono text-xs"
|
|
331
581
|
title={JSON.stringify(event.payload)}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
type Props = {
|
|
2
|
+
/**
|
|
3
|
+
* May the viewer retry/cancel jobs? `org.settings` — see `requireJobControl` in the
|
|
4
|
+
* route. Gating here only hides buttons; the server is what enforces it.
|
|
5
|
+
*/
|
|
6
|
+
canControlJobs?: boolean;
|
|
7
|
+
/** Super admins can widen jobs/events past their active organization (`?scope=all`). */
|
|
8
|
+
isSuperAdmin?: boolean;
|
|
9
|
+
};
|
|
10
|
+
declare const ActivityView: import("svelte").Component<Props, {}, "">;
|
|
2
11
|
type ActivityView = ReturnType<typeof ActivityView>;
|
|
3
12
|
export default ActivityView;
|
|
4
13
|
//# sourceMappingURL=ActivityView.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActivityView.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/ActivityView.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ActivityView.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/ActivityView.svelte.ts"],"names":[],"mappings":"AAgCC,KAAK,KAAK,GAAG;IACZ;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wFAAwF;IACxF,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AA8kBH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -52,6 +52,15 @@ export interface DocumentAdapter {
|
|
|
52
52
|
*/
|
|
53
53
|
updateDocDraft(organizationId: string, id: string, data: any, updatedBy?: string, expectedRevision?: number): Promise<Document | null>;
|
|
54
54
|
deleteDocById(organizationId: string, id: string): Promise<boolean>;
|
|
55
|
+
/**
|
|
56
|
+
* Recompute the document's precomputed full-text search index (`search_text`
|
|
57
|
+
* column, and on SQLite the FTS5 shadow table row) from caller-supplied text.
|
|
58
|
+
* Called by `CollectionAPI` as a best-effort step after `createDocument`/
|
|
59
|
+
* `updateDocDraft` succeeds — same shape as reference-index sync: not folded
|
|
60
|
+
* into the write transaction, self-healing on the next edit if it's missed.
|
|
61
|
+
* Optional so adapters without full-text search aren't broken.
|
|
62
|
+
*/
|
|
63
|
+
updateSearchText?(organizationId: string, id: string, searchText: string): Promise<void>;
|
|
55
64
|
publishDoc(organizationId: string, id: string, expectedRevision?: number): Promise<Document | null>;
|
|
56
65
|
unpublishDoc(organizationId: string, id: string, expectedRevision?: number): Promise<Document | null>;
|
|
57
66
|
countDocsByType(organizationId: string, type: string): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/document.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;6DACyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAG9B,UAAU,EAAE,MAAM;aAClB,gBAAgB,EAAE,MAAM;aACxB,eAAe,EAAE,MAAM;gBAHvC,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EACxB,eAAe,EAAE,MAAM;CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAE/B,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5D;;;;;OAKG;IACH,cAAc,CACb,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,GAAG,EACT,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC5B,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/document.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DomainEvent, AppendEventInput, Job, ScheduleJobInput, ClaimJobsOptions, ListEventsOptions, ListJobsOptions, OutboxRow, ListUnprocessedOutboxOptions, Page } from '../../types/events.js';
|
|
1
|
+
import type { DomainEvent, AppendEventInput, Job, ScheduleJobInput, ClaimJobsOptions, ListEventsOptions, ListJobsOptions, OutboxRow, ListUnprocessedOutboxOptions, OutboxHealth, Page } from '../../types/events.js';
|
|
2
2
|
/**
|
|
3
3
|
* The durable spine: an append-only domain-event log plus a DB-backed job queue.
|
|
4
4
|
* All rows are organization-scoped. (The event-log read API — `listEvents` — lands
|
|
@@ -25,6 +25,13 @@ export interface EventJobAdapter {
|
|
|
25
25
|
listUnprocessedOutbox(options: ListUnprocessedOutboxOptions): Promise<OutboxRow[]>;
|
|
26
26
|
/** Stamp `processedAt` once an outbox row has been fanned out to every subscriber. */
|
|
27
27
|
markOutboxProcessed(organizationId: string, id: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Size and age of the unprocessed backlog — the "is the relay running?" signal.
|
|
30
|
+
* Omit `organizationId` for the instance-wide figure. See {@link OutboxHealth}.
|
|
31
|
+
*/
|
|
32
|
+
outboxHealth(options: {
|
|
33
|
+
organizationId?: string;
|
|
34
|
+
}): Promise<OutboxHealth>;
|
|
28
35
|
/** Schedule a job. Idempotent when `idempotencyKey` is set: a duplicate key returns the existing job. */
|
|
29
36
|
scheduleJob(input: ScheduleJobInput): Promise<Job>;
|
|
30
37
|
/**
|
|
@@ -49,7 +56,27 @@ export interface EventJobAdapter {
|
|
|
49
56
|
}): Promise<void>;
|
|
50
57
|
/** Cancel a job (e.g. a scheduled publish the user called off): status → `cancelled`, clear the lease. */
|
|
51
58
|
cancelJob(organizationId: string, id: string): Promise<void>;
|
|
52
|
-
/**
|
|
59
|
+
/** Read a single job by id (org-scoped). Null when it doesn't exist in that org. */
|
|
60
|
+
getJob(organizationId: string, id: string): Promise<Job | null>;
|
|
61
|
+
/**
|
|
62
|
+
* Put a finished job back on the queue by hand — the operator's undo for a dead letter.
|
|
63
|
+
*
|
|
64
|
+
* Distinct from `retryJob`, which is the *runner's* backoff transition and deliberately
|
|
65
|
+
* leaves `attempts` alone. A dead-lettered job sits at `attempts === maxAttempts`, so
|
|
66
|
+
* reusing `retryJob` would hand it back to the runner only for the next claim to exhaust
|
|
67
|
+
* it again immediately. This resets the attempt counter and clears `lastError`, giving
|
|
68
|
+
* the job a fresh budget once whatever broke has been fixed.
|
|
69
|
+
*
|
|
70
|
+
* Guarded to `failed` and `cancelled` in SQL: requeueing a `pending` job is pointless and
|
|
71
|
+
* requeueing a `leased` one would race the worker currently holding it, whose settle would
|
|
72
|
+
* then overwrite the status. Returns the updated job, or null when the id doesn't exist in
|
|
73
|
+
* the org or wasn't in a requeueable state — so callers can tell "gone" from "not allowed"
|
|
74
|
+
* with a follow-up `getJob`.
|
|
75
|
+
*/
|
|
76
|
+
requeueJob(organizationId: string, id: string, options: {
|
|
77
|
+
runAt: Date;
|
|
78
|
+
}): Promise<Job | null>;
|
|
79
|
+
/** List jobs, newest first (read-only history / observability). Omit `organizationId` for instance-wide. */
|
|
53
80
|
listJobs(options: ListJobsOptions): Promise<Page<Job>>;
|
|
54
81
|
}
|
|
55
82
|
//# sourceMappingURL=events.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/events.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,WAAW,EACX,gBAAgB,EAChB,GAAG,EACH,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,4BAA4B,EAC5B,IAAI,EACJ,MAAM,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAE/B;;;;;;OAMG;IACH,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3D,8CAA8C;IAC9C,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1E,wFAAwF;IACxF,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAGnE;;;;OAIG;IACH,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACnF,sFAAsF;IACtF,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/events.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,WAAW,EACX,gBAAgB,EAChB,GAAG,EACH,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,4BAA4B,EAC5B,YAAY,EACZ,IAAI,EACJ,MAAM,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAE/B;;;;;;OAMG;IACH,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3D,8CAA8C;IAC9C,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1E,wFAAwF;IACxF,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAGnE;;;;OAIG;IACH,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACnF,sFAAsF;IACtF,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAG1E,yGAAyG;IACzG,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACnD;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxD,oCAAoC;IACpC,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CACP,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GACrC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,uFAAuF;IACvF,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,0GAA0G;IAC1G,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,oFAAoF;IACpF,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAChE;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAC9F,4GAA4G;IAC5G,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;CACvD"}
|
|
@@ -17,6 +17,7 @@ export type { UserProfileAdapter, NewUserProfileData } from './user.js';
|
|
|
17
17
|
export type { SchemaAdapter } from './schema.js';
|
|
18
18
|
export type { OrganizationAdapter } from './organization.js';
|
|
19
19
|
export type { InstanceAdapter, InstanceSettings } from './instance.js';
|
|
20
|
+
export { BOOTSTRAP_CLAIM_ID } from './instance.js';
|
|
20
21
|
export type { RolesAdapter } from './role.js';
|
|
21
22
|
export type { ReferenceAdapter, BackReferenceRow, BackReferenceLookup } from './reference.js';
|
|
22
23
|
export type { PluginSettingsAdapter, PluginSettingsRow } from './plugin-settings.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGjE,YAAY,EACX,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACrE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpE,YAAY,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC3C,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC3F,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAClF,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,YAAY,EACX,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,eAChB,SACC,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,oBAAoB,EACpB,qBAAqB;IAEtB,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7B,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAG9B;;OAEG;IACH,aAAa,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE7E;;OAEG;IACH,qBAAqB,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvE;;OAEG;IACH,kBAAkB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAExC;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7E;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,IAAI,eAAe,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACnB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,QAAQ,IAAI,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA6B,SAAQ,eAAe;IACpE,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACjD,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7E"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
import type { InstanceSettings } from '../../types/instance.js';
|
|
2
2
|
export type { InstanceSettings };
|
|
3
|
+
/**
|
|
4
|
+
* Row id holding the one-time bootstrap claim.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately not `'default'` — `get`/`updateInstanceSettings` are scoped to
|
|
7
|
+
* that row, so this one is invisible to them and can't be cleared by an ordinary
|
|
8
|
+
* settings write.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BOOTSTRAP_CLAIM_ID = "aphex:bootstrap-claim";
|
|
3
11
|
export interface InstanceAdapter {
|
|
4
12
|
getInstanceSettings(): Promise<InstanceSettings>;
|
|
5
13
|
updateInstanceSettings(settings: Partial<InstanceSettings>): Promise<InstanceSettings>;
|
|
14
|
+
/**
|
|
15
|
+
* Atomically claim the one-time bootstrap promotion. `true` means this caller
|
|
16
|
+
* won and may grant an instance role; `false` means somebody else already did.
|
|
17
|
+
*
|
|
18
|
+
* Exists because "is the instance empty?" and "insert the first profile" were
|
|
19
|
+
* two statements with a gap between them: two sign-ups arriving together could
|
|
20
|
+
* both observe an empty instance and both be promoted to super admin. Every
|
|
21
|
+
* bootstrap policy gates on `isFirstUser`, so at most one promotion is
|
|
22
|
+
* intended in all of them — this makes that atomic rather than likely.
|
|
23
|
+
*
|
|
24
|
+
* Implemented as an insert of a dedicated row that conflicts with itself, so
|
|
25
|
+
* the database decides the winner in a single statement. That matters more
|
|
26
|
+
* than it sounds: the obvious fix — wrapping the check and the insert in one
|
|
27
|
+
* transaction — holds SQLite's single write lock across the auth provider's
|
|
28
|
+
* own concurrent user and session inserts and fails sign-up with SQLITE_BUSY.
|
|
29
|
+
*
|
|
30
|
+
* Optional: an adapter that doesn't implement it keeps the old non-atomic
|
|
31
|
+
* behaviour (with a warning) rather than refusing to ever promote anyone,
|
|
32
|
+
* which would leave a fresh install with no way to get its first administrator.
|
|
33
|
+
*/
|
|
34
|
+
tryClaimBootstrap?(): Promise<boolean>;
|
|
6
35
|
}
|
|
7
36
|
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/instance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,MAAM,WAAW,eAAe;IAC/B,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjD,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/instance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC/B,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjD,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEvF;;;;;;;;;;;;;;;;;;;OAmBG;IACH,iBAAiB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACvC"}
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Row id holding the one-time bootstrap claim.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately not `'default'` — `get`/`updateInstanceSettings` are scoped to
|
|
5
|
+
* that row, so this one is invisible to them and can't be cleared by an ordinary
|
|
6
|
+
* settings write.
|
|
7
|
+
*/
|
|
8
|
+
export const BOOTSTRAP_CLAIM_ID = 'aphex:bootstrap-claim';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EventConsumerPart } from '../plugins/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Erase a deleted user's avatar — the file, not just the row.
|
|
4
|
+
*
|
|
5
|
+
* Account deletion removes the user record, and with it the only pointer to the avatar
|
|
6
|
+
* asset. Without this the image survives in object storage indefinitely, reachable by
|
|
7
|
+
* anyone holding its URL and invisible to the media browser (avatars are marked
|
|
8
|
+
* `system`), so nothing would ever surface it for cleanup. That is precisely the
|
|
9
|
+
* "personal data with no way left to find or erase it" case a right-to-erasure request
|
|
10
|
+
* has to be able to answer.
|
|
11
|
+
*
|
|
12
|
+
* Idempotent, as every consumer must be: a missing asset is a completed erasure, so a
|
|
13
|
+
* redelivery finds nothing and succeeds. It throws only when the delete itself fails, so
|
|
14
|
+
* a transient storage outage retries with backoff instead of silently giving up — the
|
|
15
|
+
* one outcome that would leave the data behind while reporting success.
|
|
16
|
+
*/
|
|
17
|
+
export declare const eraseUserAvatarConsumer: EventConsumerPart;
|
|
18
|
+
/** Every consumer core ships. Seeded into the part resolver ahead of plugin parts. */
|
|
19
|
+
export declare const BUILT_IN_EVENT_CONSUMERS: readonly EventConsumerPart[];
|
|
20
|
+
//# sourceMappingURL=built-in-consumers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in-consumers.d.ts","sourceRoot":"","sources":["../../src/lib/events/built-in-consumers.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAQ1D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB,EAAE,iBAoCrC,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,EAAE,SAAS,iBAAiB,EAA8B,CAAC"}
|