@krak-stack/registry 0.1.11 → 0.1.14

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 (51) hide show
  1. package/README.md +31 -2
  2. package/dist/components/ui/app-brand.d.ts +18 -13
  3. package/dist/components/ui/app-brand.js +48 -15
  4. package/dist/components/ui/code-block.js +10 -6
  5. package/dist/components/ui/copy-button.d.ts +1 -1
  6. package/dist/components/ui/copy-button.js +1 -1
  7. package/dist/components/ui/data-table.d.ts +1 -1
  8. package/dist/components/ui/data-table.js +21 -20
  9. package/dist/components/ui/effect-form.js +7 -6
  10. package/dist/components/ui/file-picker.js +2 -1
  11. package/dist/components/ui/form.js +17 -15
  12. package/dist/components/ui/google-map.d.ts +6 -10
  13. package/dist/components/ui/google-map.js +19 -14
  14. package/dist/components/ui/locale-switcher.js +7 -1
  15. package/dist/components/ui/sidebar-layout.js +19 -21
  16. package/dist/components/ui/theme-switcher.js +1 -1
  17. package/dist/lib/docs-core.js +165 -109
  18. package/dist/lib/documentation-toolkit.d.ts +140 -0
  19. package/dist/lib/{docs-ai.js → documentation-toolkit.js} +54 -63
  20. package/dist/lib/httpapi-cli.d.ts +6 -6
  21. package/dist/lib/httpapi-cli.js +75 -48
  22. package/dist/lib/httpapi-client.d.ts +8 -2
  23. package/dist/lib/httpapi-client.js +21 -9
  24. package/dist/lib/httpapi-helpers.d.ts +15 -21
  25. package/dist/lib/httpapi-helpers.js +38 -26
  26. package/dist/lib/httpapi-mcp.js +73 -50
  27. package/dist/lib/httpapi-toolkit.d.ts +20 -0
  28. package/dist/lib/{httpapi-ai.js → httpapi-toolkit.js} +123 -100
  29. package/dist/lib/seo.js +29 -17
  30. package/dist/lib/webfetch-toolkit.d.ts +45 -0
  31. package/dist/lib/webfetch-toolkit.js +276 -0
  32. package/dist/oxlint/anti-slop/index.js +1592 -0
  33. package/dist/services/agent/client/atom.d.ts +7 -7
  34. package/dist/services/agent/client/index.js +55 -54
  35. package/dist/services/agent/index.d.ts +71 -71
  36. package/dist/services/agent/index.js +38 -19
  37. package/dist/services/notification/channels/index.d.ts +11 -9
  38. package/dist/services/notification/channels/ses/index.d.ts +6 -6
  39. package/dist/services/notification/channels/ses/index.js +15 -11
  40. package/dist/services/notification/client/index.js +3 -2
  41. package/dist/services/notification/client/notification-menu.d.ts +9 -9
  42. package/dist/services/notification/index.d.ts +7 -6
  43. package/dist/services/notification/persistence/drizzle.js +214 -0
  44. package/dist/services/notification/persistence/index.js +227 -0
  45. package/dist/services/notification/persistence/schema.js +118 -0
  46. package/dist/services/notification/public.js +3 -2
  47. package/dist/services/s3/index.d.ts +2 -16
  48. package/dist/services/s3/index.js +12 -9
  49. package/package.json +33 -7
  50. package/dist/lib/docs-ai.d.ts +0 -142
  51. package/dist/lib/httpapi-ai.d.ts +0 -54
@@ -32,8 +32,8 @@ export type NotificationMenuState = {
32
32
  open: boolean;
33
33
  unreadCount: number;
34
34
  };
35
- type NotificationAction = (notificationIds: readonly string[]) => Promise<unknown> | unknown;
36
- export type NotificationMenuProps = {
35
+ type NotificationAction<Result = ErrorOptions["cause"]> = (notificationIds: readonly string[]) => Promise<Result> | Result | void;
36
+ export type NotificationMenuProps<ActionResult = ErrorOptions["cause"]> = {
37
37
  className?: string | undefined;
38
38
  defaultOpen?: boolean | undefined;
39
39
  error?: boolean | undefined;
@@ -42,35 +42,35 @@ export type NotificationMenuProps = {
42
42
  markReadOnOpen?: boolean | undefined;
43
43
  messages?: Partial<NotificationMenuMessages> | undefined;
44
44
  notifications: readonly NotificationItem[];
45
- onArchive?: NotificationAction | undefined;
46
- onMarkRead?: NotificationAction | undefined;
45
+ onArchive?: NotificationAction<ActionResult> | undefined;
46
+ onMarkRead?: NotificationAction<ActionResult> | undefined;
47
47
  onNavigate?: ((notification: NotificationItem) => void) | undefined;
48
48
  onOpenChange?: ((open: boolean) => void) | undefined;
49
49
  open?: boolean | undefined;
50
50
  renderItem?: ((notification: NotificationItem) => ReactNode) | undefined;
51
51
  renderTrigger?: ((state: NotificationMenuState) => ReactElement) | undefined;
52
52
  };
53
- export declare function NotificationMenu({ className, defaultOpen, error, isLoading, locale, markReadOnOpen, messages: messageOverrides, notifications, onArchive, onMarkRead, onNavigate, onOpenChange, open: controlledOpen, renderItem, renderTrigger, }: NotificationMenuProps): import("react").JSX.Element;
53
+ export declare function NotificationMenu<ActionResult = ErrorOptions["cause"]>({ className, defaultOpen, error, isLoading, locale, markReadOnOpen, messages: messageOverrides, notifications, onArchive, onMarkRead, onNavigate, onOpenChange, open: controlledOpen, renderItem, renderTrigger, }: NotificationMenuProps<ActionResult>): import("react").JSX.Element;
54
54
  export declare function NotificationMenuTrigger({ labels, unreadCount, }: {
55
55
  labels?: NotificationMenuMessages | undefined;
56
56
  unreadCount: number;
57
57
  }): import("react").JSX.Element;
58
- export declare function NotificationList({ error, isLoading, labels, locale, notifications, onArchive, onNavigate, renderItem, tab, }: {
58
+ export declare function NotificationList<ActionResult>({ error, isLoading, labels, locale, notifications, onArchive, onNavigate, renderItem, tab, }: {
59
59
  error: boolean;
60
60
  isLoading: boolean;
61
61
  labels: NotificationMenuMessages;
62
62
  locale: string;
63
63
  notifications: readonly NotificationItem[];
64
- onArchive?: NotificationAction | undefined;
64
+ onArchive?: NotificationAction<ActionResult> | undefined;
65
65
  onNavigate?: ((notification: NotificationItem) => void) | undefined;
66
66
  renderItem?: ((notification: NotificationItem) => ReactNode) | undefined;
67
67
  tab: NotificationMenuTab;
68
68
  }): import("react").JSX.Element;
69
- export declare function NotificationListItem({ labels, locale, notification, onArchive, onNavigate, renderItem, }: {
69
+ export declare function NotificationListItem<ActionResult>({ labels, locale, notification, onArchive, onNavigate, renderItem, }: {
70
70
  labels: NotificationMenuMessages;
71
71
  locale: string;
72
72
  notification: NotificationItem;
73
- onArchive?: NotificationAction | undefined;
73
+ onArchive?: NotificationAction<ActionResult> | undefined;
74
74
  onNavigate?: ((notification: NotificationItem) => void) | undefined;
75
75
  renderItem?: ((notification: NotificationItem) => ReactNode) | undefined;
76
76
  }): import("react").JSX.Element;
@@ -1,16 +1,17 @@
1
1
  import { Context, Effect, Layer } from "effect";
2
- import { NotificationChannelRegistry, type NotificationMessage, type NotificationChannelShape } from "./channels/index.js";
2
+ import { NotificationChannelRegistry, type NotificationMessage, type NotificationChannel } from "./channels/index.js";
3
3
  import { NotificationSendError } from "./schema.js";
4
- export interface NotificationServiceShape {
4
+ export interface NotificationServiceContract {
5
5
  readonly send: (message: NotificationMessage) => Effect.Effect<void, NotificationSendError>;
6
6
  }
7
- declare const NotificationService_base: Context.ServiceClass<NotificationService, "NotificationService", NotificationServiceShape> & {
8
- readonly make: Effect.Effect<NotificationServiceShape, never, NotificationChannelRegistry>;
7
+ /** @deprecated Use NotificationServiceContract. */
8
+ export { type NotificationServiceContract as NotificationServiceShape };
9
+ declare const NotificationService_base: Context.ServiceClass<NotificationService, "NotificationService", NotificationServiceContract> & {
10
+ readonly make: Effect.Effect<NotificationServiceContract, never, NotificationChannelRegistry>;
9
11
  };
10
12
  export declare class NotificationService extends NotificationService_base {
11
13
  static readonly layer: Layer.Layer<NotificationService, never, NotificationChannelRegistry>;
12
- static readonly makeLayer: (channels: ReadonlyArray<NotificationChannelShape>) => Layer.Layer<NotificationService, never, never>;
14
+ static readonly makeLayer: (channels: ReadonlyArray<NotificationChannel>) => Layer.Layer<NotificationService, never, never>;
13
15
  static readonly noopLayer: Layer.Layer<NotificationService, never, never>;
14
16
  static readonly localLayer: Layer.Layer<NotificationService, never, never>;
15
17
  }
16
- export {};
@@ -0,0 +1,214 @@
1
+ // ../../src/services/notification/persistence/drizzle.ts
2
+ import { sql } from "drizzle-orm";
3
+ import {
4
+ boolean,
5
+ check,
6
+ index,
7
+ integer,
8
+ jsonb,
9
+ pgTable,
10
+ text,
11
+ timestamp,
12
+ uniqueIndex,
13
+ uuid
14
+ } from "drizzle-orm/pg-core";
15
+
16
+ // ../../src/services/notification/persistence/schema.ts
17
+ import { Schema } from "effect";
18
+ var NOTIFICATION_DELIVERY_PURPOSES = [
19
+ "transactional",
20
+ "notification"
21
+ ];
22
+ var NOTIFICATION_DELIVERY_STATUSES = [
23
+ "queued",
24
+ "processing",
25
+ "sent",
26
+ "retrying",
27
+ "failed",
28
+ "suppressed",
29
+ "cancelled"
30
+ ];
31
+ var NotificationDeliveryPurpose = Schema.Literals(NOTIFICATION_DELIVERY_PURPOSES).annotate({ identifier: "NotificationDeliveryPurpose" });
32
+ var NotificationDeliveryStatus = Schema.Literals(NOTIFICATION_DELIVERY_STATUSES).annotate({ identifier: "NotificationDeliveryStatus" });
33
+ var NotificationId = Schema.String.pipe(Schema.brand("NotificationId")).annotate({ identifier: "NotificationId" });
34
+ var NotificationSettingId = Schema.String.pipe(Schema.brand("NotificationSettingId")).annotate({ identifier: "NotificationSettingId" });
35
+ var NotificationDeliveryId = Schema.String.pipe(Schema.brand("NotificationDeliveryId")).annotate({ identifier: "NotificationDeliveryId" });
36
+ var InboxNotificationSchema = Schema.Struct({
37
+ id: NotificationId,
38
+ idempotencyKey: Schema.NonEmptyString,
39
+ recipientUserId: Schema.NonEmptyString,
40
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
41
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
42
+ eventKey: Schema.NonEmptyString,
43
+ eventVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
44
+ locale: Schema.NonEmptyString,
45
+ title: Schema.NonEmptyString,
46
+ description: Schema.NullOr(Schema.String),
47
+ href: Schema.NullOr(Schema.String),
48
+ metadata: Schema.Json,
49
+ createdAt: Schema.Date,
50
+ readAt: Schema.NullOr(Schema.Date),
51
+ archivedAt: Schema.NullOr(Schema.Date)
52
+ }).annotate({ identifier: "InboxNotification" });
53
+ var NotificationSettingSchema = Schema.Struct({
54
+ id: NotificationSettingId,
55
+ recipientUserId: Schema.NonEmptyString,
56
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
57
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
58
+ eventKey: Schema.NullOr(Schema.NonEmptyString),
59
+ channel: Schema.NonEmptyString,
60
+ enabled: Schema.Boolean,
61
+ createdAt: Schema.Date,
62
+ updatedAt: Schema.Date
63
+ }).annotate({ identifier: "NotificationSetting" });
64
+ var NotificationDeliverySchema = Schema.Struct({
65
+ id: NotificationDeliveryId,
66
+ notificationId: Schema.NullOr(NotificationId),
67
+ idempotencyKey: Schema.NonEmptyString,
68
+ recipientUserId: Schema.NullOr(Schema.NonEmptyString),
69
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
70
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
71
+ eventKey: Schema.NonEmptyString,
72
+ eventVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
73
+ channel: Schema.NonEmptyString,
74
+ purpose: NotificationDeliveryPurpose,
75
+ template: Schema.NullOr(Schema.NonEmptyString),
76
+ recipientAddress: Schema.NonEmptyString,
77
+ recipientName: Schema.NullOr(Schema.NonEmptyString),
78
+ payloadVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
79
+ payload: Schema.Json,
80
+ status: NotificationDeliveryStatus,
81
+ attempts: Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0))),
82
+ maxAttempts: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
83
+ provider: Schema.NullOr(Schema.NonEmptyString),
84
+ providerMessageId: Schema.NullOr(Schema.NonEmptyString),
85
+ errorMessage: Schema.NullOr(Schema.String),
86
+ scheduledFor: Schema.Date,
87
+ processingAt: Schema.NullOr(Schema.Date),
88
+ lastAttemptAt: Schema.NullOr(Schema.Date),
89
+ leaseExpiresAt: Schema.NullOr(Schema.Date),
90
+ claimedBy: Schema.NullOr(Schema.NonEmptyString),
91
+ sentAt: Schema.NullOr(Schema.Date),
92
+ failedAt: Schema.NullOr(Schema.Date),
93
+ suppressedAt: Schema.NullOr(Schema.Date),
94
+ cancelledAt: Schema.NullOr(Schema.Date),
95
+ createdAt: Schema.Date,
96
+ updatedAt: Schema.Date
97
+ }).annotate({ identifier: "NotificationDelivery" });
98
+ var EmailDeliveryPayloadV1 = Schema.Struct({
99
+ from: Schema.optional(Schema.NonEmptyString),
100
+ to: Schema.Union([
101
+ Schema.NonEmptyString,
102
+ Schema.NonEmptyArray(Schema.NonEmptyString)
103
+ ]),
104
+ cc: Schema.optional(Schema.Array(Schema.NonEmptyString)),
105
+ bcc: Schema.optional(Schema.Array(Schema.NonEmptyString)),
106
+ replyTo: Schema.optional(Schema.Array(Schema.NonEmptyString)),
107
+ subject: Schema.NonEmptyString,
108
+ text: Schema.optional(Schema.NonEmptyString),
109
+ html: Schema.optional(Schema.NonEmptyString)
110
+ }).pipe(Schema.refine((payload) => payload.text !== undefined || payload.html !== undefined, { message: "Email delivery payload requires text or html" })).annotate({ identifier: "EmailDeliveryPayloadV1" });
111
+ var PersistedNotificationDeliveryPayload = Schema.Union([
112
+ Schema.Struct({
113
+ channel: Schema.Literal("email"),
114
+ payloadVersion: Schema.Literal(1),
115
+ payload: EmailDeliveryPayloadV1
116
+ })
117
+ ]).annotate({ identifier: "PersistedNotificationDeliveryPayload" });
118
+ var decodeNotificationDeliveryPayload = Schema.decodeUnknownEffect(PersistedNotificationDeliveryPayload);
119
+
120
+ // ../../src/services/notification/persistence/drizzle.ts
121
+ var timestampWithTimezone = (name) => timestamp(name, { withTimezone: true });
122
+ var nonEmpty = (column) => sql`length(btrim(${column})) > 0`;
123
+ var notifications = pgTable("notifications", {
124
+ id: uuid("id").defaultRandom().primaryKey(),
125
+ idempotencyKey: text("idempotency_key").notNull(),
126
+ recipientUserId: text("recipient_user_id").notNull(),
127
+ organizationId: text("organization_id"),
128
+ workspaceId: text("workspace_id"),
129
+ eventKey: text("event_key").notNull(),
130
+ eventVersion: integer("event_version").default(1).notNull(),
131
+ locale: text("locale").notNull(),
132
+ title: text("title").notNull(),
133
+ description: text("description"),
134
+ href: text("href"),
135
+ metadata: jsonb("metadata").$type().default({}).notNull(),
136
+ createdAt: timestampWithTimezone("created_at").defaultNow().notNull(),
137
+ readAt: timestampWithTimezone("read_at"),
138
+ archivedAt: timestampWithTimezone("archived_at")
139
+ }, (table) => [
140
+ uniqueIndex("notifications_idempotency_key_uidx").on(table.idempotencyKey),
141
+ index("notifications_recipient_inbox_created_idx").on(table.recipientUserId, table.organizationId, table.workspaceId, table.archivedAt, table.createdAt),
142
+ index("notifications_recipient_unread_idx").on(table.recipientUserId, table.organizationId, table.workspaceId, table.readAt),
143
+ check("notifications_non_empty_fields_check", sql`${nonEmpty(table.idempotencyKey)} and ${nonEmpty(table.recipientUserId)} and ${nonEmpty(table.eventKey)} and ${nonEmpty(table.locale)} and ${nonEmpty(table.title)} and (${table.organizationId} is null or ${nonEmpty(table.organizationId)}) and (${table.workspaceId} is null or ${nonEmpty(table.workspaceId)})`),
144
+ check("notifications_event_version_check", sql`${table.eventVersion} > 0`)
145
+ ]);
146
+ var notificationSettings = pgTable("notification_settings", {
147
+ id: uuid("id").defaultRandom().primaryKey(),
148
+ recipientUserId: text("recipient_user_id").notNull(),
149
+ organizationId: text("organization_id"),
150
+ workspaceId: text("workspace_id"),
151
+ eventKey: text("event_key"),
152
+ channel: text("channel").notNull(),
153
+ enabled: boolean("enabled").default(true).notNull(),
154
+ createdAt: timestampWithTimezone("created_at").defaultNow().notNull(),
155
+ updatedAt: timestampWithTimezone("updated_at").defaultNow().notNull()
156
+ }, (table) => [
157
+ uniqueIndex("notification_settings_scope_channel_uidx").on(table.recipientUserId, sql`coalesce(${table.organizationId}, '')`, sql`coalesce(${table.workspaceId}, '')`, sql`coalesce(${table.eventKey}, '')`, table.channel),
158
+ index("notification_settings_recipient_channel_idx").on(table.recipientUserId, table.channel),
159
+ check("notification_settings_non_empty_fields_check", sql`${nonEmpty(table.recipientUserId)} and ${nonEmpty(table.channel)} and (${table.organizationId} is null or ${nonEmpty(table.organizationId)}) and (${table.workspaceId} is null or ${nonEmpty(table.workspaceId)}) and (${table.eventKey} is null or ${nonEmpty(table.eventKey)})`)
160
+ ]);
161
+ var notificationDeliveries = pgTable("notification_deliveries", {
162
+ id: uuid("id").defaultRandom().primaryKey(),
163
+ notificationId: uuid("notification_id").references(() => notifications.id, {
164
+ onDelete: "set null"
165
+ }),
166
+ idempotencyKey: text("idempotency_key").notNull(),
167
+ recipientUserId: text("recipient_user_id"),
168
+ organizationId: text("organization_id"),
169
+ workspaceId: text("workspace_id"),
170
+ eventKey: text("event_key").notNull(),
171
+ eventVersion: integer("event_version").default(1).notNull(),
172
+ channel: text("channel").notNull(),
173
+ purpose: text("purpose").notNull(),
174
+ template: text("template"),
175
+ recipientAddress: text("recipient_address").notNull(),
176
+ recipientName: text("recipient_name"),
177
+ payloadVersion: integer("payload_version").default(1).notNull(),
178
+ payload: jsonb("payload").$type().notNull(),
179
+ status: text("status").default("queued").notNull(),
180
+ attempts: integer("attempts").default(0).notNull(),
181
+ maxAttempts: integer("max_attempts").default(5).notNull(),
182
+ provider: text("provider"),
183
+ providerMessageId: text("provider_message_id"),
184
+ errorMessage: text("error_message"),
185
+ scheduledFor: timestampWithTimezone("scheduled_for").defaultNow().notNull(),
186
+ processingAt: timestampWithTimezone("processing_at"),
187
+ lastAttemptAt: timestampWithTimezone("last_attempt_at"),
188
+ leaseExpiresAt: timestampWithTimezone("lease_expires_at"),
189
+ claimedBy: text("claimed_by"),
190
+ sentAt: timestampWithTimezone("sent_at"),
191
+ failedAt: timestampWithTimezone("failed_at"),
192
+ suppressedAt: timestampWithTimezone("suppressed_at"),
193
+ cancelledAt: timestampWithTimezone("cancelled_at"),
194
+ createdAt: timestampWithTimezone("created_at").defaultNow().notNull(),
195
+ updatedAt: timestampWithTimezone("updated_at").defaultNow().notNull()
196
+ }, (table) => [
197
+ uniqueIndex("notification_deliveries_idempotency_key_uidx").on(table.idempotencyKey),
198
+ index("notification_deliveries_claim_idx").on(table.channel, table.status, table.scheduledFor),
199
+ index("notification_deliveries_notification_id_idx").on(table.notificationId),
200
+ index("notification_deliveries_recipient_address_idx").on(table.recipientAddress),
201
+ index("notification_deliveries_scope_created_idx").on(table.organizationId, table.workspaceId, table.createdAt),
202
+ index("notification_deliveries_template_idx").on(table.template),
203
+ check("notification_deliveries_non_empty_fields_check", sql`${nonEmpty(table.idempotencyKey)} and ${nonEmpty(table.eventKey)} and ${nonEmpty(table.channel)} and ${nonEmpty(table.recipientAddress)} and (${table.recipientUserId} is null or ${nonEmpty(table.recipientUserId)}) and (${table.organizationId} is null or ${nonEmpty(table.organizationId)}) and (${table.workspaceId} is null or ${nonEmpty(table.workspaceId)}) and (${table.template} is null or ${nonEmpty(table.template)}) and (${table.recipientName} is null or ${nonEmpty(table.recipientName)}) and (${table.provider} is null or ${nonEmpty(table.provider)}) and (${table.providerMessageId} is null or ${nonEmpty(table.providerMessageId)}) and (${table.claimedBy} is null or ${nonEmpty(table.claimedBy)})`),
204
+ check("notification_deliveries_purpose_check", sql`${table.purpose} in (${sql.join(NOTIFICATION_DELIVERY_PURPOSES.map((value) => sql`${value}`), sql`, `)})`),
205
+ check("notification_deliveries_status_check", sql`${table.status} in (${sql.join(NOTIFICATION_DELIVERY_STATUSES.map((value) => sql`${value}`), sql`, `)})`),
206
+ check("notification_deliveries_versions_check", sql`${table.eventVersion} > 0 and ${table.payloadVersion} > 0`),
207
+ check("notification_deliveries_attempts_check", sql`${table.attempts} >= 0 and ${table.maxAttempts} > 0 and ${table.attempts} <= ${table.maxAttempts}`),
208
+ check("notification_deliveries_lease_check", sql`(${table.claimedBy} is null and ${table.leaseExpiresAt} is null) or (${table.claimedBy} is not null and ${table.leaseExpiresAt} is not null)`)
209
+ ]);
210
+ export {
211
+ notifications,
212
+ notificationSettings,
213
+ notificationDeliveries
214
+ };
@@ -0,0 +1,227 @@
1
+ // ../../src/services/notification/persistence/drizzle.ts
2
+ import { sql } from "drizzle-orm";
3
+ import {
4
+ boolean,
5
+ check,
6
+ index,
7
+ integer,
8
+ jsonb,
9
+ pgTable,
10
+ text,
11
+ timestamp,
12
+ uniqueIndex,
13
+ uuid
14
+ } from "drizzle-orm/pg-core";
15
+
16
+ // ../../src/services/notification/persistence/schema.ts
17
+ import { Schema } from "effect";
18
+ var NOTIFICATION_DELIVERY_PURPOSES = [
19
+ "transactional",
20
+ "notification"
21
+ ];
22
+ var NOTIFICATION_DELIVERY_STATUSES = [
23
+ "queued",
24
+ "processing",
25
+ "sent",
26
+ "retrying",
27
+ "failed",
28
+ "suppressed",
29
+ "cancelled"
30
+ ];
31
+ var NotificationDeliveryPurpose = Schema.Literals(NOTIFICATION_DELIVERY_PURPOSES).annotate({ identifier: "NotificationDeliveryPurpose" });
32
+ var NotificationDeliveryStatus = Schema.Literals(NOTIFICATION_DELIVERY_STATUSES).annotate({ identifier: "NotificationDeliveryStatus" });
33
+ var NotificationId = Schema.String.pipe(Schema.brand("NotificationId")).annotate({ identifier: "NotificationId" });
34
+ var NotificationSettingId = Schema.String.pipe(Schema.brand("NotificationSettingId")).annotate({ identifier: "NotificationSettingId" });
35
+ var NotificationDeliveryId = Schema.String.pipe(Schema.brand("NotificationDeliveryId")).annotate({ identifier: "NotificationDeliveryId" });
36
+ var InboxNotificationSchema = Schema.Struct({
37
+ id: NotificationId,
38
+ idempotencyKey: Schema.NonEmptyString,
39
+ recipientUserId: Schema.NonEmptyString,
40
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
41
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
42
+ eventKey: Schema.NonEmptyString,
43
+ eventVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
44
+ locale: Schema.NonEmptyString,
45
+ title: Schema.NonEmptyString,
46
+ description: Schema.NullOr(Schema.String),
47
+ href: Schema.NullOr(Schema.String),
48
+ metadata: Schema.Json,
49
+ createdAt: Schema.Date,
50
+ readAt: Schema.NullOr(Schema.Date),
51
+ archivedAt: Schema.NullOr(Schema.Date)
52
+ }).annotate({ identifier: "InboxNotification" });
53
+ var NotificationSettingSchema = Schema.Struct({
54
+ id: NotificationSettingId,
55
+ recipientUserId: Schema.NonEmptyString,
56
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
57
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
58
+ eventKey: Schema.NullOr(Schema.NonEmptyString),
59
+ channel: Schema.NonEmptyString,
60
+ enabled: Schema.Boolean,
61
+ createdAt: Schema.Date,
62
+ updatedAt: Schema.Date
63
+ }).annotate({ identifier: "NotificationSetting" });
64
+ var NotificationDeliverySchema = Schema.Struct({
65
+ id: NotificationDeliveryId,
66
+ notificationId: Schema.NullOr(NotificationId),
67
+ idempotencyKey: Schema.NonEmptyString,
68
+ recipientUserId: Schema.NullOr(Schema.NonEmptyString),
69
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
70
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
71
+ eventKey: Schema.NonEmptyString,
72
+ eventVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
73
+ channel: Schema.NonEmptyString,
74
+ purpose: NotificationDeliveryPurpose,
75
+ template: Schema.NullOr(Schema.NonEmptyString),
76
+ recipientAddress: Schema.NonEmptyString,
77
+ recipientName: Schema.NullOr(Schema.NonEmptyString),
78
+ payloadVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
79
+ payload: Schema.Json,
80
+ status: NotificationDeliveryStatus,
81
+ attempts: Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0))),
82
+ maxAttempts: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
83
+ provider: Schema.NullOr(Schema.NonEmptyString),
84
+ providerMessageId: Schema.NullOr(Schema.NonEmptyString),
85
+ errorMessage: Schema.NullOr(Schema.String),
86
+ scheduledFor: Schema.Date,
87
+ processingAt: Schema.NullOr(Schema.Date),
88
+ lastAttemptAt: Schema.NullOr(Schema.Date),
89
+ leaseExpiresAt: Schema.NullOr(Schema.Date),
90
+ claimedBy: Schema.NullOr(Schema.NonEmptyString),
91
+ sentAt: Schema.NullOr(Schema.Date),
92
+ failedAt: Schema.NullOr(Schema.Date),
93
+ suppressedAt: Schema.NullOr(Schema.Date),
94
+ cancelledAt: Schema.NullOr(Schema.Date),
95
+ createdAt: Schema.Date,
96
+ updatedAt: Schema.Date
97
+ }).annotate({ identifier: "NotificationDelivery" });
98
+ var EmailDeliveryPayloadV1 = Schema.Struct({
99
+ from: Schema.optional(Schema.NonEmptyString),
100
+ to: Schema.Union([
101
+ Schema.NonEmptyString,
102
+ Schema.NonEmptyArray(Schema.NonEmptyString)
103
+ ]),
104
+ cc: Schema.optional(Schema.Array(Schema.NonEmptyString)),
105
+ bcc: Schema.optional(Schema.Array(Schema.NonEmptyString)),
106
+ replyTo: Schema.optional(Schema.Array(Schema.NonEmptyString)),
107
+ subject: Schema.NonEmptyString,
108
+ text: Schema.optional(Schema.NonEmptyString),
109
+ html: Schema.optional(Schema.NonEmptyString)
110
+ }).pipe(Schema.refine((payload) => payload.text !== undefined || payload.html !== undefined, { message: "Email delivery payload requires text or html" })).annotate({ identifier: "EmailDeliveryPayloadV1" });
111
+ var PersistedNotificationDeliveryPayload = Schema.Union([
112
+ Schema.Struct({
113
+ channel: Schema.Literal("email"),
114
+ payloadVersion: Schema.Literal(1),
115
+ payload: EmailDeliveryPayloadV1
116
+ })
117
+ ]).annotate({ identifier: "PersistedNotificationDeliveryPayload" });
118
+ var decodeNotificationDeliveryPayload = Schema.decodeUnknownEffect(PersistedNotificationDeliveryPayload);
119
+
120
+ // ../../src/services/notification/persistence/drizzle.ts
121
+ var timestampWithTimezone = (name) => timestamp(name, { withTimezone: true });
122
+ var nonEmpty = (column) => sql`length(btrim(${column})) > 0`;
123
+ var notifications = pgTable("notifications", {
124
+ id: uuid("id").defaultRandom().primaryKey(),
125
+ idempotencyKey: text("idempotency_key").notNull(),
126
+ recipientUserId: text("recipient_user_id").notNull(),
127
+ organizationId: text("organization_id"),
128
+ workspaceId: text("workspace_id"),
129
+ eventKey: text("event_key").notNull(),
130
+ eventVersion: integer("event_version").default(1).notNull(),
131
+ locale: text("locale").notNull(),
132
+ title: text("title").notNull(),
133
+ description: text("description"),
134
+ href: text("href"),
135
+ metadata: jsonb("metadata").$type().default({}).notNull(),
136
+ createdAt: timestampWithTimezone("created_at").defaultNow().notNull(),
137
+ readAt: timestampWithTimezone("read_at"),
138
+ archivedAt: timestampWithTimezone("archived_at")
139
+ }, (table) => [
140
+ uniqueIndex("notifications_idempotency_key_uidx").on(table.idempotencyKey),
141
+ index("notifications_recipient_inbox_created_idx").on(table.recipientUserId, table.organizationId, table.workspaceId, table.archivedAt, table.createdAt),
142
+ index("notifications_recipient_unread_idx").on(table.recipientUserId, table.organizationId, table.workspaceId, table.readAt),
143
+ check("notifications_non_empty_fields_check", sql`${nonEmpty(table.idempotencyKey)} and ${nonEmpty(table.recipientUserId)} and ${nonEmpty(table.eventKey)} and ${nonEmpty(table.locale)} and ${nonEmpty(table.title)} and (${table.organizationId} is null or ${nonEmpty(table.organizationId)}) and (${table.workspaceId} is null or ${nonEmpty(table.workspaceId)})`),
144
+ check("notifications_event_version_check", sql`${table.eventVersion} > 0`)
145
+ ]);
146
+ var notificationSettings = pgTable("notification_settings", {
147
+ id: uuid("id").defaultRandom().primaryKey(),
148
+ recipientUserId: text("recipient_user_id").notNull(),
149
+ organizationId: text("organization_id"),
150
+ workspaceId: text("workspace_id"),
151
+ eventKey: text("event_key"),
152
+ channel: text("channel").notNull(),
153
+ enabled: boolean("enabled").default(true).notNull(),
154
+ createdAt: timestampWithTimezone("created_at").defaultNow().notNull(),
155
+ updatedAt: timestampWithTimezone("updated_at").defaultNow().notNull()
156
+ }, (table) => [
157
+ uniqueIndex("notification_settings_scope_channel_uidx").on(table.recipientUserId, sql`coalesce(${table.organizationId}, '')`, sql`coalesce(${table.workspaceId}, '')`, sql`coalesce(${table.eventKey}, '')`, table.channel),
158
+ index("notification_settings_recipient_channel_idx").on(table.recipientUserId, table.channel),
159
+ check("notification_settings_non_empty_fields_check", sql`${nonEmpty(table.recipientUserId)} and ${nonEmpty(table.channel)} and (${table.organizationId} is null or ${nonEmpty(table.organizationId)}) and (${table.workspaceId} is null or ${nonEmpty(table.workspaceId)}) and (${table.eventKey} is null or ${nonEmpty(table.eventKey)})`)
160
+ ]);
161
+ var notificationDeliveries = pgTable("notification_deliveries", {
162
+ id: uuid("id").defaultRandom().primaryKey(),
163
+ notificationId: uuid("notification_id").references(() => notifications.id, {
164
+ onDelete: "set null"
165
+ }),
166
+ idempotencyKey: text("idempotency_key").notNull(),
167
+ recipientUserId: text("recipient_user_id"),
168
+ organizationId: text("organization_id"),
169
+ workspaceId: text("workspace_id"),
170
+ eventKey: text("event_key").notNull(),
171
+ eventVersion: integer("event_version").default(1).notNull(),
172
+ channel: text("channel").notNull(),
173
+ purpose: text("purpose").notNull(),
174
+ template: text("template"),
175
+ recipientAddress: text("recipient_address").notNull(),
176
+ recipientName: text("recipient_name"),
177
+ payloadVersion: integer("payload_version").default(1).notNull(),
178
+ payload: jsonb("payload").$type().notNull(),
179
+ status: text("status").default("queued").notNull(),
180
+ attempts: integer("attempts").default(0).notNull(),
181
+ maxAttempts: integer("max_attempts").default(5).notNull(),
182
+ provider: text("provider"),
183
+ providerMessageId: text("provider_message_id"),
184
+ errorMessage: text("error_message"),
185
+ scheduledFor: timestampWithTimezone("scheduled_for").defaultNow().notNull(),
186
+ processingAt: timestampWithTimezone("processing_at"),
187
+ lastAttemptAt: timestampWithTimezone("last_attempt_at"),
188
+ leaseExpiresAt: timestampWithTimezone("lease_expires_at"),
189
+ claimedBy: text("claimed_by"),
190
+ sentAt: timestampWithTimezone("sent_at"),
191
+ failedAt: timestampWithTimezone("failed_at"),
192
+ suppressedAt: timestampWithTimezone("suppressed_at"),
193
+ cancelledAt: timestampWithTimezone("cancelled_at"),
194
+ createdAt: timestampWithTimezone("created_at").defaultNow().notNull(),
195
+ updatedAt: timestampWithTimezone("updated_at").defaultNow().notNull()
196
+ }, (table) => [
197
+ uniqueIndex("notification_deliveries_idempotency_key_uidx").on(table.idempotencyKey),
198
+ index("notification_deliveries_claim_idx").on(table.channel, table.status, table.scheduledFor),
199
+ index("notification_deliveries_notification_id_idx").on(table.notificationId),
200
+ index("notification_deliveries_recipient_address_idx").on(table.recipientAddress),
201
+ index("notification_deliveries_scope_created_idx").on(table.organizationId, table.workspaceId, table.createdAt),
202
+ index("notification_deliveries_template_idx").on(table.template),
203
+ check("notification_deliveries_non_empty_fields_check", sql`${nonEmpty(table.idempotencyKey)} and ${nonEmpty(table.eventKey)} and ${nonEmpty(table.channel)} and ${nonEmpty(table.recipientAddress)} and (${table.recipientUserId} is null or ${nonEmpty(table.recipientUserId)}) and (${table.organizationId} is null or ${nonEmpty(table.organizationId)}) and (${table.workspaceId} is null or ${nonEmpty(table.workspaceId)}) and (${table.template} is null or ${nonEmpty(table.template)}) and (${table.recipientName} is null or ${nonEmpty(table.recipientName)}) and (${table.provider} is null or ${nonEmpty(table.provider)}) and (${table.providerMessageId} is null or ${nonEmpty(table.providerMessageId)}) and (${table.claimedBy} is null or ${nonEmpty(table.claimedBy)})`),
204
+ check("notification_deliveries_purpose_check", sql`${table.purpose} in (${sql.join(NOTIFICATION_DELIVERY_PURPOSES.map((value) => sql`${value}`), sql`, `)})`),
205
+ check("notification_deliveries_status_check", sql`${table.status} in (${sql.join(NOTIFICATION_DELIVERY_STATUSES.map((value) => sql`${value}`), sql`, `)})`),
206
+ check("notification_deliveries_versions_check", sql`${table.eventVersion} > 0 and ${table.payloadVersion} > 0`),
207
+ check("notification_deliveries_attempts_check", sql`${table.attempts} >= 0 and ${table.maxAttempts} > 0 and ${table.attempts} <= ${table.maxAttempts}`),
208
+ check("notification_deliveries_lease_check", sql`(${table.claimedBy} is null and ${table.leaseExpiresAt} is null) or (${table.claimedBy} is not null and ${table.leaseExpiresAt} is not null)`)
209
+ ]);
210
+ export {
211
+ notifications,
212
+ notificationSettings,
213
+ notificationDeliveries,
214
+ decodeNotificationDeliveryPayload,
215
+ PersistedNotificationDeliveryPayload,
216
+ NotificationSettingSchema,
217
+ NotificationSettingId,
218
+ NotificationId,
219
+ NotificationDeliveryStatus,
220
+ NotificationDeliverySchema,
221
+ NotificationDeliveryPurpose,
222
+ NotificationDeliveryId,
223
+ NOTIFICATION_DELIVERY_STATUSES,
224
+ NOTIFICATION_DELIVERY_PURPOSES,
225
+ InboxNotificationSchema,
226
+ EmailDeliveryPayloadV1
227
+ };
@@ -0,0 +1,118 @@
1
+ // ../../src/services/notification/persistence/schema.ts
2
+ import { Schema } from "effect";
3
+ var NOTIFICATION_DELIVERY_PURPOSES = [
4
+ "transactional",
5
+ "notification"
6
+ ];
7
+ var NOTIFICATION_DELIVERY_STATUSES = [
8
+ "queued",
9
+ "processing",
10
+ "sent",
11
+ "retrying",
12
+ "failed",
13
+ "suppressed",
14
+ "cancelled"
15
+ ];
16
+ var NotificationDeliveryPurpose = Schema.Literals(NOTIFICATION_DELIVERY_PURPOSES).annotate({ identifier: "NotificationDeliveryPurpose" });
17
+ var NotificationDeliveryStatus = Schema.Literals(NOTIFICATION_DELIVERY_STATUSES).annotate({ identifier: "NotificationDeliveryStatus" });
18
+ var NotificationId = Schema.String.pipe(Schema.brand("NotificationId")).annotate({ identifier: "NotificationId" });
19
+ var NotificationSettingId = Schema.String.pipe(Schema.brand("NotificationSettingId")).annotate({ identifier: "NotificationSettingId" });
20
+ var NotificationDeliveryId = Schema.String.pipe(Schema.brand("NotificationDeliveryId")).annotate({ identifier: "NotificationDeliveryId" });
21
+ var InboxNotificationSchema = Schema.Struct({
22
+ id: NotificationId,
23
+ idempotencyKey: Schema.NonEmptyString,
24
+ recipientUserId: Schema.NonEmptyString,
25
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
26
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
27
+ eventKey: Schema.NonEmptyString,
28
+ eventVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
29
+ locale: Schema.NonEmptyString,
30
+ title: Schema.NonEmptyString,
31
+ description: Schema.NullOr(Schema.String),
32
+ href: Schema.NullOr(Schema.String),
33
+ metadata: Schema.Json,
34
+ createdAt: Schema.Date,
35
+ readAt: Schema.NullOr(Schema.Date),
36
+ archivedAt: Schema.NullOr(Schema.Date)
37
+ }).annotate({ identifier: "InboxNotification" });
38
+ var NotificationSettingSchema = Schema.Struct({
39
+ id: NotificationSettingId,
40
+ recipientUserId: Schema.NonEmptyString,
41
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
42
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
43
+ eventKey: Schema.NullOr(Schema.NonEmptyString),
44
+ channel: Schema.NonEmptyString,
45
+ enabled: Schema.Boolean,
46
+ createdAt: Schema.Date,
47
+ updatedAt: Schema.Date
48
+ }).annotate({ identifier: "NotificationSetting" });
49
+ var NotificationDeliverySchema = Schema.Struct({
50
+ id: NotificationDeliveryId,
51
+ notificationId: Schema.NullOr(NotificationId),
52
+ idempotencyKey: Schema.NonEmptyString,
53
+ recipientUserId: Schema.NullOr(Schema.NonEmptyString),
54
+ organizationId: Schema.NullOr(Schema.NonEmptyString),
55
+ workspaceId: Schema.NullOr(Schema.NonEmptyString),
56
+ eventKey: Schema.NonEmptyString,
57
+ eventVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
58
+ channel: Schema.NonEmptyString,
59
+ purpose: NotificationDeliveryPurpose,
60
+ template: Schema.NullOr(Schema.NonEmptyString),
61
+ recipientAddress: Schema.NonEmptyString,
62
+ recipientName: Schema.NullOr(Schema.NonEmptyString),
63
+ payloadVersion: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
64
+ payload: Schema.Json,
65
+ status: NotificationDeliveryStatus,
66
+ attempts: Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0))),
67
+ maxAttempts: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
68
+ provider: Schema.NullOr(Schema.NonEmptyString),
69
+ providerMessageId: Schema.NullOr(Schema.NonEmptyString),
70
+ errorMessage: Schema.NullOr(Schema.String),
71
+ scheduledFor: Schema.Date,
72
+ processingAt: Schema.NullOr(Schema.Date),
73
+ lastAttemptAt: Schema.NullOr(Schema.Date),
74
+ leaseExpiresAt: Schema.NullOr(Schema.Date),
75
+ claimedBy: Schema.NullOr(Schema.NonEmptyString),
76
+ sentAt: Schema.NullOr(Schema.Date),
77
+ failedAt: Schema.NullOr(Schema.Date),
78
+ suppressedAt: Schema.NullOr(Schema.Date),
79
+ cancelledAt: Schema.NullOr(Schema.Date),
80
+ createdAt: Schema.Date,
81
+ updatedAt: Schema.Date
82
+ }).annotate({ identifier: "NotificationDelivery" });
83
+ var EmailDeliveryPayloadV1 = Schema.Struct({
84
+ from: Schema.optional(Schema.NonEmptyString),
85
+ to: Schema.Union([
86
+ Schema.NonEmptyString,
87
+ Schema.NonEmptyArray(Schema.NonEmptyString)
88
+ ]),
89
+ cc: Schema.optional(Schema.Array(Schema.NonEmptyString)),
90
+ bcc: Schema.optional(Schema.Array(Schema.NonEmptyString)),
91
+ replyTo: Schema.optional(Schema.Array(Schema.NonEmptyString)),
92
+ subject: Schema.NonEmptyString,
93
+ text: Schema.optional(Schema.NonEmptyString),
94
+ html: Schema.optional(Schema.NonEmptyString)
95
+ }).pipe(Schema.refine((payload) => payload.text !== undefined || payload.html !== undefined, { message: "Email delivery payload requires text or html" })).annotate({ identifier: "EmailDeliveryPayloadV1" });
96
+ var PersistedNotificationDeliveryPayload = Schema.Union([
97
+ Schema.Struct({
98
+ channel: Schema.Literal("email"),
99
+ payloadVersion: Schema.Literal(1),
100
+ payload: EmailDeliveryPayloadV1
101
+ })
102
+ ]).annotate({ identifier: "PersistedNotificationDeliveryPayload" });
103
+ var decodeNotificationDeliveryPayload = Schema.decodeUnknownEffect(PersistedNotificationDeliveryPayload);
104
+ export {
105
+ decodeNotificationDeliveryPayload,
106
+ PersistedNotificationDeliveryPayload,
107
+ NotificationSettingSchema,
108
+ NotificationSettingId,
109
+ NotificationId,
110
+ NotificationDeliveryStatus,
111
+ NotificationDeliverySchema,
112
+ NotificationDeliveryPurpose,
113
+ NotificationDeliveryId,
114
+ NOTIFICATION_DELIVERY_STATUSES,
115
+ NOTIFICATION_DELIVERY_PURPOSES,
116
+ InboxNotificationSchema,
117
+ EmailDeliveryPayloadV1
118
+ };