@cosmicdrift/kumiko-bundled-features 0.383.1 → 0.384.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.
Files changed (126) hide show
  1. package/dist/audit/event-classification.d.ts +8 -0
  2. package/dist/audit/event-classification.js +69 -0
  3. package/dist/audit/feature.js +3 -3
  4. package/dist/audit/handlers/audit-events.d.ts +25 -3
  5. package/dist/audit/handlers/audit-events.js +41 -7
  6. package/dist/audit/handlers/details-all-tenants.query.d.ts +3 -0
  7. package/dist/audit/handlers/details-all-tenants.query.js +2 -5
  8. package/dist/audit/handlers/details.query.d.ts +3 -0
  9. package/dist/audit/handlers/details.query.js +5 -3
  10. package/dist/audit/handlers/list-all-tenants.query.d.ts +9 -2
  11. package/dist/audit/handlers/list-all-tenants.query.js +10 -8
  12. package/dist/audit/handlers/list.query.d.ts +8 -0
  13. package/dist/audit/handlers/list.query.js +12 -4
  14. package/dist/audit/screens.d.ts +37 -0
  15. package/dist/audit/screens.js +26 -4
  16. package/dist/audit/web/audit-event-cell.d.ts +4 -0
  17. package/dist/audit/web/audit-event-cell.js +20 -0
  18. package/dist/audit/web/audit-event-labels.d.ts +7 -0
  19. package/dist/audit/web/audit-event-labels.js +23 -0
  20. package/dist/audit/web/client-plugin.js +6 -1
  21. package/dist/audit/web/constants.d.ts +8 -0
  22. package/dist/audit/web/constants.js +7 -0
  23. package/dist/audit/web/i18n.js +48 -1
  24. package/dist/auth-email-password/feature.js +3 -2
  25. package/dist/auth-email-password/handlers/login-options.query.d.ts +5 -0
  26. package/dist/auth-email-password/handlers/login-options.query.js +17 -0
  27. package/dist/auth-email-password/index.d.ts +1 -1
  28. package/dist/auth-email-password/index.js +1 -1
  29. package/dist/auth-email-password/{auth-paths.d.ts → web/auth-paths.d.ts} +5 -3
  30. package/dist/auth-email-password/{auth-paths.js → web/auth-paths.js} +5 -3
  31. package/dist/auth-email-password/web/client-plugin.d.ts +5 -0
  32. package/dist/auth-email-password/web/client-plugin.js +2 -0
  33. package/dist/auth-email-password/web/constants.d.ts +1 -0
  34. package/dist/auth-email-password/web/constants.js +1 -0
  35. package/dist/auth-email-password/web/default-auth-pages-gate.d.ts +4 -0
  36. package/dist/auth-email-password/web/default-auth-pages-gate.js +28 -0
  37. package/dist/auth-email-password/web/login-screen.d.ts +13 -18
  38. package/dist/auth-email-password/web/login-screen.js +31 -19
  39. package/dist/auth-mfa/schema/user-mfa.d.ts +6 -126
  40. package/dist/billing-foundation/entities.d.ts +8 -168
  41. package/dist/billing-foundation/projection.d.ts +8 -168
  42. package/dist/cap-counter/entity.d.ts +1 -21
  43. package/dist/compliance-profiles/schema/profile-selection.d.ts +2 -28
  44. package/dist/config/table.d.ts +6 -126
  45. package/dist/custom-fields/entity.d.ts +4 -84
  46. package/dist/data-retention/schema/tenant-retention-override.d.ts +6 -112
  47. package/dist/delivery/tables.d.ts +6 -126
  48. package/dist/document-ingest-foundation/entity.d.ts +6 -112
  49. package/dist/folders/entity.d.ts +8 -168
  50. package/dist/form-draft/entity.d.ts +2 -42
  51. package/dist/inbound-mail-foundation/entities.d.ts +25 -525
  52. package/dist/inbound-mail-foundation/projection.d.ts +20 -420
  53. package/dist/jobs/feature.js +22 -117
  54. package/dist/jobs/handlers/consumer.write.d.ts +37 -0
  55. package/dist/jobs/handlers/consumer.write.js +59 -0
  56. package/dist/jobs/handlers/consumers.query.d.ts +52 -0
  57. package/dist/jobs/handlers/consumers.query.js +114 -0
  58. package/dist/jobs/job-run-table.d.ts +6 -126
  59. package/dist/jobs/screens.d.ts +6 -0
  60. package/dist/jobs/screens.js +241 -0
  61. package/dist/jobs/web/constants.d.ts +20 -0
  62. package/dist/jobs/web/constants.js +21 -0
  63. package/dist/jobs/web/i18n.js +41 -0
  64. package/dist/ledger/entity.d.ts +13 -273
  65. package/dist/managed-pages/table.d.ts +12 -252
  66. package/dist/notes-history/entity.d.ts +14 -280
  67. package/dist/personal-access-tokens/schema/api-token.d.ts +6 -126
  68. package/dist/secrets/i18n.d.ts +0 -3
  69. package/dist/secrets/i18n.js +0 -3
  70. package/dist/secrets/table.d.ts +1 -21
  71. package/dist/sessions/constants.d.ts +2 -1
  72. package/dist/sessions/constants.js +2 -1
  73. package/dist/sessions/handlers/detail.query.d.ts +5 -0
  74. package/dist/sessions/handlers/detail.query.js +7 -3
  75. package/dist/sessions/handlers/list.query.d.ts +5 -0
  76. package/dist/sessions/handlers/list.query.js +16 -10
  77. package/dist/sessions/handlers/mine.query.d.ts +5 -0
  78. package/dist/sessions/handlers/mine.query.js +15 -9
  79. package/dist/sessions/schema/user-session.d.ts +4 -84
  80. package/dist/sessions/screens.js +22 -8
  81. package/dist/sessions/web/client-plugin.d.ts +6 -0
  82. package/dist/sessions/web/client-plugin.js +11 -0
  83. package/dist/sessions/web/constants.d.ts +3 -0
  84. package/dist/sessions/web/constants.js +3 -0
  85. package/dist/sessions/web/default-translations.d.ts +2 -0
  86. package/dist/sessions/web/default-translations.js +3 -0
  87. package/dist/sessions/web/i18n.js +5 -1
  88. package/dist/sessions/web/index.d.ts +1 -0
  89. package/dist/sessions/web/index.js +1 -0
  90. package/dist/sessions/web/session-device-cell.d.ts +3 -0
  91. package/dist/sessions/web/session-device-cell.js +16 -0
  92. package/dist/sessions/web/user-agent.d.ts +26 -0
  93. package/dist/sessions/web/user-agent.js +58 -0
  94. package/dist/tags/entity.d.ts +9 -189
  95. package/dist/template-resolver/feature.d.ts +1 -0
  96. package/dist/template-resolver/feature.js +2 -0
  97. package/dist/template-resolver/handlers/overview.query.d.ts +5 -0
  98. package/dist/template-resolver/handlers/overview.query.js +19 -2
  99. package/dist/template-resolver/handlers/tenant-override-counts.query.d.ts +17 -0
  100. package/dist/template-resolver/handlers/tenant-override-counts.query.js +35 -0
  101. package/dist/template-resolver/handlers/tenant-override-selection.d.ts +12 -0
  102. package/dist/template-resolver/handlers/tenant-override-selection.js +34 -0
  103. package/dist/template-resolver/handlers/tenant-overrides.query.js +3 -29
  104. package/dist/template-resolver/table.d.ts +20 -350
  105. package/dist/template-resolver/user-content-table.d.ts +12 -238
  106. package/dist/template-resolver/web/qualified-names.d.ts +1 -0
  107. package/dist/template-resolver/web/qualified-names.js +1 -0
  108. package/dist/tenant/invitation-table.d.ts +6 -126
  109. package/dist/tenant/membership-table.d.ts +4 -84
  110. package/dist/tenant/schema/tenant.d.ts +6 -126
  111. package/dist/tier-engine/entity.d.ts +1 -21
  112. package/dist/tier-engine/tier-resolver.d.ts +1 -21
  113. package/dist/user/schema/user.d.ts +12 -252
  114. package/dist/user-data-rights/feature.js +33 -33
  115. package/dist/user-data-rights/schema/download-attempt.d.ts +14 -294
  116. package/dist/user-data-rights/schema/download-token.d.ts +8 -168
  117. package/dist/user-data-rights/schema/export-job.d.ts +8 -154
  118. package/dist/user-data-rights/web/i18n.js +4 -1
  119. package/dist/waitlist/entity.d.ts +16 -322
  120. package/package.json +17 -9
  121. package/src/audit/changes.json +6 -0
  122. package/src/auth-email-password/changes.json +6 -0
  123. package/src/jobs/changes.json +6 -0
  124. package/src/sessions/changes.json +6 -0
  125. package/src/template-resolver/changes.json +6 -0
  126. package/src/user-data-rights/changes.json +18 -0
@@ -0,0 +1,37 @@
1
+ import * as z from "zod";
2
+ export declare const consumerRestartWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<string, z.ZodObject<{
3
+ name: z.ZodString;
4
+ instanceId: z.ZodString;
5
+ }, z.core.$strip>, {
6
+ name: string;
7
+ instanceId: string;
8
+ status: string;
9
+ skippedEventId: string | null;
10
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
11
+ export declare const consumerSkipWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<string, z.ZodObject<{
12
+ name: z.ZodString;
13
+ instanceId: z.ZodString;
14
+ }, z.core.$strip>, {
15
+ name: string;
16
+ instanceId: string;
17
+ status: string;
18
+ skippedEventId: string | null;
19
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
20
+ export declare const consumerDisableWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<string, z.ZodObject<{
21
+ name: z.ZodString;
22
+ instanceId: z.ZodString;
23
+ }, z.core.$strip>, {
24
+ name: string;
25
+ instanceId: string;
26
+ status: string;
27
+ skippedEventId: string | null;
28
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
29
+ export declare const consumerEnableWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<string, z.ZodObject<{
30
+ name: z.ZodString;
31
+ instanceId: z.ZodString;
32
+ }, z.core.$strip>, {
33
+ name: string;
34
+ instanceId: string;
35
+ status: string;
36
+ skippedEventId: string | null;
37
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
@@ -0,0 +1,59 @@
1
+ import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { InternalError, UnprocessableError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
3
+ import { ConsumerStatuses, ConsumerTransitionError, disableConsumer, enableConsumer, restartConsumer, skipPoisonEvent, } from "@cosmicdrift/kumiko-framework/pipeline";
4
+ import * as z from "zod";
5
+ import { JobErrors } from "../web/constants.js";
6
+ const consumerTargetSchema = z.object({ name: z.string().min(1), instanceId: z.string().min(1) });
7
+ const CONSUMER_STATE_REASON = "event consumer state is global dispatcher state, not tenant data";
8
+ function rejected(code, i18nKey) {
9
+ return writeFailure(new UnprocessableError(code, { i18nKey }));
10
+ }
11
+ function defineConsumerWrite(name, description, transition) {
12
+ return defineWriteHandler({
13
+ name,
14
+ description,
15
+ schema: consumerTargetSchema,
16
+ access: { roles: ["SystemAdmin"] },
17
+ // Operator recovery for people only; skip drops an event for good.
18
+ agent: { expose: false },
19
+ handler: async (event, ctx) => {
20
+ if (!ctx.systemDb) {
21
+ throw new InternalError({
22
+ message: `jobs:write:${name} requires ctx.systemDb (feature must declare r.systemScope())`,
23
+ });
24
+ }
25
+ const db = ctx.systemDb.unsafeRaw(CONSUMER_STATE_REASON);
26
+ try {
27
+ const next = await transition(db, event.payload.name, event.payload.instanceId);
28
+ if (next.skippedEventId === null) {
29
+ return rejected(JobErrors.consumerNothingToSkip, "jobs.errors.consumerNothingToSkip");
30
+ }
31
+ return {
32
+ isSuccess: true,
33
+ data: {
34
+ name: next.name,
35
+ instanceId: next.instanceId,
36
+ status: next.status,
37
+ skippedEventId: next.skippedEventId?.toString() ?? null,
38
+ },
39
+ };
40
+ }
41
+ catch (e) {
42
+ if (e instanceof ConsumerTransitionError) {
43
+ return e.rejection === "unknown-consumer"
44
+ ? rejected(JobErrors.consumerUnknown, "jobs.errors.consumerUnknown")
45
+ : rejected(JobErrors.consumerWrongStatus, "jobs.errors.consumerWrongStatus");
46
+ }
47
+ ctx.log?.error(`jobs:write:${name} failed: ${e instanceof Error ? e.message : String(e)}`, {
48
+ consumer: event.payload.name,
49
+ instanceId: event.payload.instanceId,
50
+ });
51
+ return rejected(JobErrors.consumerTransitionFailed, "jobs.errors.consumerTransitionFailed");
52
+ }
53
+ },
54
+ });
55
+ }
56
+ export const consumerRestartWrite = defineConsumerWrite("consumer-restart", "Sets a dead event consumer back to idle so it retries the event that stopped it; use it after a transient failure is fixed.", restartConsumer);
57
+ export const consumerSkipWrite = defineConsumerWrite("consumer-skip", "Moves a stuck event consumer past the event that keeps failing; that event is never delivered to this consumer, so use it only for events that can never succeed.", (db, consumerName, instanceId) => skipPoisonEvent(db, consumerName, instanceId, { requireStatus: ConsumerStatuses.dead }));
58
+ export const consumerDisableWrite = defineConsumerWrite("consumer-disable", "Pauses an event consumer; the dispatcher skips it until it is enabled again.", disableConsumer);
59
+ export const consumerEnableWrite = defineConsumerWrite("consumer-enable", "Resumes a paused event consumer from where it stopped.", enableConsumer);
@@ -0,0 +1,52 @@
1
+ import * as z from "zod";
2
+ export declare function consumerRowId(name: string, instanceId: string): string;
3
+ export declare function splitConsumerRowId(id: string): {
4
+ name: string;
5
+ instanceId: string;
6
+ } | null;
7
+ export declare const consumersQuery: import("@cosmicdrift/kumiko-types/define-handler").QueryHandlerDefinition<"consumers", z.ZodObject<{
8
+ filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
9
+ field: z.ZodLiteral<"status">;
10
+ op: z.ZodLiteral<"in">;
11
+ value: z.ZodArray<z.ZodEnum<{
12
+ dead: "dead";
13
+ disabled: "disabled";
14
+ idle: "idle";
15
+ "never-run": "never-run";
16
+ processing: "processing";
17
+ }>>;
18
+ }, z.core.$strict>>>;
19
+ sort: z.ZodOptional<z.ZodEnum<{
20
+ attempts: "attempts";
21
+ lag: "lag";
22
+ name: "name";
23
+ status: "status";
24
+ }>>;
25
+ sortDirection: z.ZodOptional<z.ZodEnum<{
26
+ asc: "asc";
27
+ desc: "desc";
28
+ }>>;
29
+ }, z.core.$strip>, {
30
+ rows: {
31
+ id: string;
32
+ name: string;
33
+ instanceId: string;
34
+ status: string;
35
+ lag: number;
36
+ attempts: number;
37
+ lastError: string | null;
38
+ }[];
39
+ nextCursor: null;
40
+ }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
41
+ export declare const consumerDetailQuery: import("@cosmicdrift/kumiko-types/define-handler").QueryHandlerDefinition<"consumer-details", z.ZodObject<{
42
+ consumerId: z.ZodString;
43
+ }, z.core.$strip>, {
44
+ id: string;
45
+ name: string;
46
+ instanceId: string;
47
+ status: string;
48
+ lag: number;
49
+ attempts: number;
50
+ lastError: string | null;
51
+ updatedAt: string | null;
52
+ } | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -0,0 +1,114 @@
1
+ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
3
+ import { getAllConsumerProgress, getConsumerState, SEARCH_CONSUMER_NAME, SSE_BROADCAST_CONSUMER_NAME, } from "@cosmicdrift/kumiko-framework/pipeline";
4
+ import * as z from "zod";
5
+ import { CONSUMER_ID_SEPARATOR, CONSUMER_STATUSES, isConsumerStatus, } from "../web/constants.js";
6
+ const LAST_ERROR_PREVIEW_LENGTH = 90;
7
+ // Dead consumers are what support looks for, so they lead the default order.
8
+ const STATUS_RANK = {
9
+ dead: 0,
10
+ disabled: 1,
11
+ processing: 2,
12
+ "never-run": 3,
13
+ idle: 4,
14
+ };
15
+ export function consumerRowId(name, instanceId) {
16
+ return `${name}${CONSUMER_ID_SEPARATOR}${instanceId}`;
17
+ }
18
+ export function splitConsumerRowId(id) {
19
+ const at = id.lastIndexOf(CONSUMER_ID_SEPARATOR);
20
+ if (at <= 0)
21
+ return null;
22
+ return { name: id.slice(0, at), instanceId: id.slice(at + 1) };
23
+ }
24
+ function registeredConsumerNames(registry) {
25
+ return [
26
+ SSE_BROADCAST_CONSUMER_NAME,
27
+ SEARCH_CONSUMER_NAME,
28
+ ...registry.getAllMultiStreamProjections().keys(),
29
+ ];
30
+ }
31
+ function previewOf(error) {
32
+ if (error === null || error.length <= LAST_ERROR_PREVIEW_LENGTH)
33
+ return error;
34
+ return `${error.slice(0, LAST_ERROR_PREVIEW_LENGTH).trimEnd()}…`;
35
+ }
36
+ function toRow(c) {
37
+ return {
38
+ id: consumerRowId(c.name, c.instanceId),
39
+ name: c.name,
40
+ instanceId: c.instanceId,
41
+ status: c.status,
42
+ lag: Number(c.lag),
43
+ attempts: c.attempts,
44
+ lastError: previewOf(c.lastError),
45
+ };
46
+ }
47
+ const statusFilterSchema = z.strictObject({
48
+ field: z.literal("status"),
49
+ op: z.literal("in"),
50
+ value: z.array(z.enum(CONSUMER_STATUSES)),
51
+ });
52
+ export const consumersQuery = defineQueryHandler({
53
+ name: "consumers",
54
+ description: "Lists every event consumer (projections, search indexer, SSE broadcaster) with status, lag behind the event store and last error, dead consumers first; use it to find a stuck consumer.",
55
+ schema: z.object({
56
+ filters: z.array(statusFilterSchema).max(1).optional(),
57
+ sort: z.enum(["name", "status", "lag", "attempts"]).optional(),
58
+ sortDirection: z.enum(["asc", "desc"]).optional(),
59
+ }),
60
+ access: { roles: ["SystemAdmin"] },
61
+ handler: async (query, ctx) => {
62
+ if (!ctx.systemDb) {
63
+ throw new InternalError({
64
+ message: "jobs:query:consumers requires ctx.systemDb (feature must declare r.systemScope())",
65
+ });
66
+ }
67
+ const db = ctx.systemDb.unsafeRaw("event consumer state is global dispatcher state, not tenant data");
68
+ const progress = await getAllConsumerProgress(db, registeredConsumerNames(ctx.registry));
69
+ const statuses = query.payload.filters?.[0]?.value;
70
+ const visible = statuses
71
+ ? progress.filter((c) => statuses.some((s) => s === c.status))
72
+ : progress;
73
+ const direction = query.payload.sortDirection === "desc" ? -1 : 1;
74
+ const sort = query.payload.sort;
75
+ const compare = (a, b) => {
76
+ if (sort === "name")
77
+ return a.name.localeCompare(b.name) * direction;
78
+ if (sort === "lag")
79
+ return Number(a.lag - b.lag) * direction;
80
+ if (sort === "attempts")
81
+ return (a.attempts - b.attempts) * direction;
82
+ const rank = (c) => isConsumerStatus(c.status) ? STATUS_RANK[c.status] : 5;
83
+ return (rank(a) - rank(b)) * direction || a.name.localeCompare(b.name);
84
+ };
85
+ return { rows: [...visible].sort(compare).map(toRow), nextCursor: null };
86
+ },
87
+ });
88
+ export const consumerDetailQuery = defineQueryHandler({
89
+ name: "consumer-details",
90
+ description: "Returns one event consumer with its status, lag, attempts, the full last error and the time of its last state change; use it to decide between restart, skip and pause.",
91
+ schema: z.object({ consumerId: z.string().min(1) }),
92
+ access: { roles: ["SystemAdmin"] },
93
+ handler: async (query, ctx) => {
94
+ if (!ctx.systemDb) {
95
+ throw new InternalError({
96
+ message: "jobs:query:consumer-details requires ctx.systemDb (feature must declare r.systemScope())",
97
+ });
98
+ }
99
+ const target = splitConsumerRowId(query.payload.consumerId);
100
+ if (!target)
101
+ return null;
102
+ const db = ctx.systemDb.unsafeRaw("event consumer state is global dispatcher state, not tenant data");
103
+ const all = await getAllConsumerProgress(db, registeredConsumerNames(ctx.registry));
104
+ const progress = all.find((c) => c.name === target.name && c.instanceId === target.instanceId);
105
+ if (!progress)
106
+ return null;
107
+ const state = await getConsumerState(db, target.name, target.instanceId);
108
+ return {
109
+ ...toRow(progress),
110
+ lastError: progress.lastError,
111
+ updatedAt: state ? state.updatedAt.toString() : null,
112
+ };
113
+ },
114
+ });
@@ -2,119 +2,19 @@ import { type EntityTableMeta, type WritableTable } from "@cosmicdrift/kumiko-fr
2
2
  export type JobRunStatus = "queued" | "running" | "completed" | "failed";
3
3
  export type JobLogLevel = "info" | "warn" | "error";
4
4
  export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
5
- readonly jobName: {
6
- readonly type: "text";
7
- readonly description?: string;
8
- readonly maxLength?: number;
9
- readonly minLength?: number;
10
- readonly autoComplete?: string;
11
- readonly required?: boolean;
12
- readonly searchable?: boolean;
13
- readonly sortable?: boolean;
14
- readonly filterable?: boolean;
15
- readonly encrypted?: boolean;
16
- readonly sensitive?: boolean;
17
- readonly writeOnly?: boolean;
18
- readonly readAsInstruction?: boolean;
19
- readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
20
- readonly default?: string;
21
- readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
22
- readonly multiline?: boolean | {
23
- readonly rows?: number;
24
- };
25
- } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
5
+ readonly jobName: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
26
6
  required: true;
27
7
  };
28
- readonly bullJobId: {
29
- readonly type: "text";
30
- readonly description?: string;
31
- readonly maxLength?: number;
32
- readonly minLength?: number;
33
- readonly autoComplete?: string;
34
- readonly required?: boolean;
35
- readonly searchable?: boolean;
36
- readonly sortable?: boolean;
37
- readonly filterable?: boolean;
38
- readonly encrypted?: boolean;
39
- readonly sensitive?: boolean;
40
- readonly writeOnly?: boolean;
41
- readonly readAsInstruction?: boolean;
42
- readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
43
- readonly default?: string;
44
- readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
45
- readonly multiline?: boolean | {
46
- readonly rows?: number;
47
- };
48
- } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
8
+ readonly bullJobId: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
49
9
  required: true;
50
10
  };
51
- readonly status: {
52
- readonly type: "text";
53
- readonly description?: string;
54
- readonly maxLength?: number;
55
- readonly minLength?: number;
56
- readonly autoComplete?: string;
57
- readonly required?: boolean;
58
- readonly searchable?: boolean;
59
- readonly sortable?: boolean;
60
- readonly filterable?: boolean;
61
- readonly encrypted?: boolean;
62
- readonly sensitive?: boolean;
63
- readonly writeOnly?: boolean;
64
- readonly readAsInstruction?: boolean;
65
- readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
66
- readonly default?: string;
67
- readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
68
- readonly multiline?: boolean | {
69
- readonly rows?: number;
70
- };
71
- } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
11
+ readonly status: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
72
12
  required: true;
73
13
  };
74
- readonly payload: {
75
- readonly type: "text";
76
- readonly description?: string;
77
- readonly maxLength?: number;
78
- readonly minLength?: number;
79
- readonly autoComplete?: string;
80
- readonly required?: boolean;
81
- readonly searchable?: boolean;
82
- readonly sortable?: boolean;
83
- readonly filterable?: boolean;
84
- readonly encrypted?: boolean;
85
- readonly sensitive?: boolean;
86
- readonly writeOnly?: boolean;
87
- readonly readAsInstruction?: boolean;
88
- readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
89
- readonly default?: string;
90
- readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
91
- readonly multiline?: boolean | {
92
- readonly rows?: number;
93
- };
94
- } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
14
+ readonly payload: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
95
15
  required: false;
96
16
  };
97
- readonly error: {
98
- readonly type: "text";
99
- readonly description?: string;
100
- readonly maxLength?: number;
101
- readonly minLength?: number;
102
- readonly autoComplete?: string;
103
- readonly required?: boolean;
104
- readonly searchable?: boolean;
105
- readonly sortable?: boolean;
106
- readonly filterable?: boolean;
107
- readonly encrypted?: boolean;
108
- readonly sensitive?: boolean;
109
- readonly writeOnly?: boolean;
110
- readonly readAsInstruction?: boolean;
111
- readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
112
- readonly default?: string;
113
- readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
114
- readonly multiline?: boolean | {
115
- readonly rows?: number;
116
- };
117
- } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
17
+ readonly error: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
118
18
  required: false;
119
19
  };
120
20
  readonly attempt: {
@@ -185,27 +85,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
185
85
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
186
86
  required: false;
187
87
  };
188
- readonly triggeredById: {
189
- readonly type: "text";
190
- readonly description?: string;
191
- readonly maxLength?: number;
192
- readonly minLength?: number;
193
- readonly autoComplete?: string;
194
- readonly required?: boolean;
195
- readonly searchable?: boolean;
196
- readonly sortable?: boolean;
197
- readonly filterable?: boolean;
198
- readonly encrypted?: boolean;
199
- readonly sensitive?: boolean;
200
- readonly writeOnly?: boolean;
201
- readonly readAsInstruction?: boolean;
202
- readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
203
- readonly default?: string;
204
- readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
205
- readonly multiline?: boolean | {
206
- readonly rows?: number;
207
- };
208
- } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
88
+ readonly triggeredById: import("@cosmicdrift/kumiko-types/fields").EntityTextFieldDef & {
209
89
  required: false;
210
90
  };
211
91
  }, "tenant">;
@@ -0,0 +1,6 @@
1
+ import { type ActionFormScreenDefinition, type ProjectionDetailScreenDefinition, type ProjectionListScreenDefinition } from "@cosmicdrift/kumiko-framework/engine";
2
+ export declare const jobRunsScreen: ProjectionListScreenDefinition;
3
+ export declare const jobTriggerScreen: ActionFormScreenDefinition;
4
+ export declare const jobRunDetailScreen: ProjectionDetailScreenDefinition;
5
+ export declare const eventConsumersScreen: ProjectionListScreenDefinition;
6
+ export declare const eventConsumerDetailScreen: ProjectionDetailScreenDefinition;
@@ -0,0 +1,241 @@
1
+ import { i18nKey, } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { CONSUMER_INSTANCE_OPTION_KEY_PREFIX, CONSUMER_STATUS_OPTION_KEY_PREFIX, CONSUMER_STATUSES, EVENT_CONSUMER_DETAIL_SCREEN_ID, EVENT_CONSUMERS_SCREEN_ID, JOB_RUN_DETAIL_SCREEN_ID, JOB_RUNS_SCREEN_ID, JobHandlers, JobQueries, } from "./web/constants.js";
3
+ const systemAdminAccess = { roles: ["SystemAdmin"] };
4
+ export const jobRunsScreen = {
5
+ id: JOB_RUNS_SCREEN_ID,
6
+ type: "projectionList",
7
+ query: JobQueries.list,
8
+ columns: [
9
+ { field: "jobName", label: i18nKey("jobs.runs.col.job") },
10
+ { field: "status", label: i18nKey("jobs.runs.col.status") },
11
+ {
12
+ field: "startedAt",
13
+ label: i18nKey("jobs.runs.col.started"),
14
+ renderer: { format: "timestamp" },
15
+ },
16
+ { field: "duration", label: i18nKey("jobs.runs.col.duration") },
17
+ ],
18
+ defaultSort: { field: "startedAt", dir: "desc" },
19
+ facets: [
20
+ {
21
+ field: "status",
22
+ type: "select",
23
+ label: i18nKey("jobs.runs.filter.status"),
24
+ options: [
25
+ { value: "queued", label: i18nKey("jobs.runs.filter.queued") },
26
+ { value: "running", label: i18nKey("jobs.runs.filter.running") },
27
+ { value: "completed", label: i18nKey("jobs.runs.filter.completed") },
28
+ { value: "failed", label: i18nKey("jobs.runs.filter.failed") },
29
+ ],
30
+ },
31
+ ],
32
+ rowActions: [
33
+ {
34
+ kind: "navigate",
35
+ id: "open",
36
+ label: i18nKey("jobs.runs.open"),
37
+ screen: JOB_RUN_DETAIL_SCREEN_ID,
38
+ entityId: "id",
39
+ rowClick: true,
40
+ },
41
+ ],
42
+ toolbarActions: [
43
+ {
44
+ kind: "drawer",
45
+ id: "trigger",
46
+ label: i18nKey("jobs.trigger.title"),
47
+ screen: "job-trigger",
48
+ style: "primary",
49
+ },
50
+ ],
51
+ pagination: "infinite",
52
+ access: systemAdminAccess,
53
+ };
54
+ export const jobTriggerScreen = {
55
+ id: "job-trigger",
56
+ type: "actionForm",
57
+ handler: JobHandlers.trigger,
58
+ fields: {
59
+ jobName: { type: "text", required: true },
60
+ payload: { type: "longText", multiline: true, default: "{}" },
61
+ },
62
+ layout: { sections: [{ fields: ["jobName", "payload"] }] },
63
+ submitLabel: i18nKey("jobs.trigger.submit"),
64
+ access: systemAdminAccess,
65
+ description: "jobs.screen.job-trigger.subtitle",
66
+ };
67
+ export const jobRunDetailScreen = {
68
+ id: JOB_RUN_DETAIL_SCREEN_ID,
69
+ type: "projectionDetail",
70
+ query: JobQueries.details,
71
+ idParam: "runId",
72
+ fieldLabels: {
73
+ jobName: i18nKey("jobs.detail.field.job"),
74
+ status: i18nKey("jobs.detail.field.status"),
75
+ id: i18nKey("jobs.detail.field.id"),
76
+ startedAt: i18nKey("jobs.detail.field.started"),
77
+ finishedAt: i18nKey("jobs.detail.field.finished"),
78
+ duration: i18nKey("jobs.detail.field.duration"),
79
+ error: i18nKey("jobs.detail.field.error"),
80
+ logs: i18nKey("jobs.detail.logs"),
81
+ },
82
+ layout: {
83
+ sections: [
84
+ {
85
+ fields: [
86
+ "jobName",
87
+ "status",
88
+ "id",
89
+ { field: "startedAt", renderer: { format: "timestamp" } },
90
+ { field: "finishedAt", renderer: { format: "timestamp" } },
91
+ "duration",
92
+ "error",
93
+ ],
94
+ },
95
+ // No section `title` here (fw#2312 label-dedup fix): the section
96
+ // holds exactly one field, so a title would repeat the field's own
97
+ // label (rendered by RenderField as the Field's heading) verbatim.
98
+ {
99
+ fields: [{ field: "logs", renderer: { format: "json" } }],
100
+ },
101
+ ],
102
+ },
103
+ actions: [
104
+ {
105
+ kind: "writeHandler",
106
+ id: "retry",
107
+ label: i18nKey("jobs.detail.retry"),
108
+ handler: JobHandlers.retry,
109
+ payload: { map: { runId: "id" } },
110
+ visible: { field: "status", eq: "failed" },
111
+ style: "primary",
112
+ },
113
+ ],
114
+ description: "jobs.screen.job-run-detail.subtitle",
115
+ listScreenId: JOB_RUNS_SCREEN_ID,
116
+ access: systemAdminAccess,
117
+ };
118
+ export const eventConsumersScreen = {
119
+ id: EVENT_CONSUMERS_SCREEN_ID,
120
+ type: "projectionList",
121
+ query: JobQueries.consumers,
122
+ columns: [
123
+ { field: "name", label: i18nKey("jobs.consumers.col.name") },
124
+ {
125
+ field: "status",
126
+ label: i18nKey("jobs.consumers.col.status"),
127
+ renderer: { format: "enumOption", keyPrefix: CONSUMER_STATUS_OPTION_KEY_PREFIX },
128
+ },
129
+ { field: "lag", label: i18nKey("jobs.consumers.col.lag"), hideOnNarrow: true },
130
+ { field: "attempts", label: i18nKey("jobs.consumers.col.attempts"), hideOnNarrow: true },
131
+ { field: "lastError", label: i18nKey("jobs.consumers.col.lastError") },
132
+ ],
133
+ defaultSort: { field: "status", dir: "asc" },
134
+ facets: [
135
+ {
136
+ field: "status",
137
+ type: "select",
138
+ label: i18nKey("jobs.consumers.col.status"),
139
+ options: CONSUMER_STATUSES.map((status) => ({
140
+ value: status,
141
+ label: i18nKey(`${CONSUMER_STATUS_OPTION_KEY_PREFIX}${status}`),
142
+ })),
143
+ },
144
+ ],
145
+ rowActions: [
146
+ {
147
+ kind: "navigate",
148
+ id: "open",
149
+ label: i18nKey("jobs.runs.open"),
150
+ screen: EVENT_CONSUMER_DETAIL_SCREEN_ID,
151
+ entityId: "id",
152
+ rowClick: true,
153
+ },
154
+ ],
155
+ pagination: "infinite",
156
+ access: systemAdminAccess,
157
+ description: "jobs.screen.event-consumers.subtitle",
158
+ };
159
+ export const eventConsumerDetailScreen = {
160
+ id: EVENT_CONSUMER_DETAIL_SCREEN_ID,
161
+ type: "projectionDetail",
162
+ query: JobQueries.consumerDetails,
163
+ idParam: "consumerId",
164
+ fieldLabels: {
165
+ name: i18nKey("jobs.consumers.col.name"),
166
+ instanceId: i18nKey("jobs.consumers.field.instanceId"),
167
+ status: i18nKey("jobs.consumers.col.status"),
168
+ lag: i18nKey("jobs.consumers.col.lag"),
169
+ attempts: i18nKey("jobs.consumers.col.attempts"),
170
+ lastError: i18nKey("jobs.consumers.col.lastError"),
171
+ updatedAt: i18nKey("jobs.consumers.field.updatedAt"),
172
+ },
173
+ layout: {
174
+ sections: [
175
+ {
176
+ fields: [
177
+ "name",
178
+ {
179
+ field: "instanceId",
180
+ renderer: { format: "enumOption", keyPrefix: CONSUMER_INSTANCE_OPTION_KEY_PREFIX },
181
+ },
182
+ {
183
+ field: "status",
184
+ renderer: { format: "enumOption", keyPrefix: CONSUMER_STATUS_OPTION_KEY_PREFIX },
185
+ },
186
+ "lag",
187
+ "attempts",
188
+ { field: "updatedAt", renderer: { format: "timestamp" } },
189
+ ],
190
+ },
191
+ { fields: ["lastError"] },
192
+ ],
193
+ },
194
+ actions: [
195
+ {
196
+ kind: "writeHandler",
197
+ id: "restart",
198
+ icon: "refresh",
199
+ label: i18nKey("jobs.consumers.restart"),
200
+ handler: JobHandlers.consumerRestart,
201
+ payload: { map: { name: "name", instanceId: "instanceId" } },
202
+ visible: { field: "status", eq: "dead" },
203
+ style: "primary",
204
+ },
205
+ {
206
+ kind: "writeHandler",
207
+ id: "skip",
208
+ icon: "arrow-right",
209
+ label: i18nKey("jobs.consumers.skip"),
210
+ handler: JobHandlers.consumerSkip,
211
+ payload: { map: { name: "name", instanceId: "instanceId" } },
212
+ visible: { field: "status", eq: "dead" },
213
+ confirm: i18nKey("jobs.consumers.skip.confirm"),
214
+ style: "danger",
215
+ },
216
+ {
217
+ kind: "writeHandler",
218
+ id: "disable",
219
+ icon: "x",
220
+ label: i18nKey("jobs.consumers.disable"),
221
+ handler: JobHandlers.consumerDisable,
222
+ payload: { map: { name: "name", instanceId: "instanceId" } },
223
+ visible: { field: "status", ne: "disabled" },
224
+ style: "secondary",
225
+ },
226
+ {
227
+ kind: "writeHandler",
228
+ id: "enable",
229
+ icon: "check",
230
+ label: i18nKey("jobs.consumers.enable"),
231
+ handler: JobHandlers.consumerEnable,
232
+ payload: { map: { name: "name", instanceId: "instanceId" } },
233
+ visible: { field: "status", eq: "disabled" },
234
+ style: "primary",
235
+ },
236
+ ],
237
+ primaryAction: "restart",
238
+ description: "jobs.screen.event-consumer-detail.subtitle",
239
+ listScreenId: EVENT_CONSUMERS_SCREEN_ID,
240
+ access: systemAdminAccess,
241
+ };