@headless-lms/adapter-db 0.1.0 → 0.3.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 (138) hide show
  1. package/README.md +79 -0
  2. package/dist/client.d.ts +1 -1
  3. package/dist/client.js.map +1 -1
  4. package/dist/index.d.ts +7 -5
  5. package/dist/index.js +8 -6
  6. package/dist/migrate.js.map +1 -1
  7. package/dist/repositories/admin.d.ts +23 -0
  8. package/dist/repositories/admin.js +393 -0
  9. package/dist/repositories/admin.js.map +1 -0
  10. package/dist/repositories/assets.d.ts +6 -2
  11. package/dist/repositories/assets.js +53 -9
  12. package/dist/repositories/assets.js.map +1 -1
  13. package/dist/repositories/automations.d.ts +12 -6
  14. package/dist/repositories/automations.js +79 -11
  15. package/dist/repositories/automations.js.map +1 -1
  16. package/dist/repositories/chats.d.ts +55 -0
  17. package/dist/repositories/chats.js +454 -0
  18. package/dist/repositories/chats.js.map +1 -0
  19. package/dist/repositories/content.d.ts +44 -7
  20. package/dist/repositories/content.js +458 -24
  21. package/dist/repositories/content.js.map +1 -1
  22. package/dist/repositories/credentials.js +2 -0
  23. package/dist/repositories/credentials.js.map +1 -1
  24. package/dist/repositories/discussion.d.ts +11 -4
  25. package/dist/repositories/discussion.js +72 -15
  26. package/dist/repositories/discussion.js.map +1 -1
  27. package/dist/repositories/entitlements.d.ts +36 -10
  28. package/dist/repositories/entitlements.js +238 -23
  29. package/dist/repositories/entitlements.js.map +1 -1
  30. package/dist/repositories/grant-covers.d.ts +20 -0
  31. package/dist/repositories/grant-covers.js +55 -0
  32. package/dist/repositories/grant-covers.js.map +1 -0
  33. package/dist/repositories/identity.d.ts +4 -2
  34. package/dist/repositories/identity.js +34 -1
  35. package/dist/repositories/identity.js.map +1 -1
  36. package/dist/repositories/integrations.d.ts +1 -1
  37. package/dist/repositories/integrations.js +2 -0
  38. package/dist/repositories/integrations.js.map +1 -1
  39. package/dist/repositories/member.d.ts +16 -0
  40. package/dist/repositories/member.js +63 -0
  41. package/dist/repositories/member.js.map +1 -0
  42. package/dist/repositories/members.js +4 -2
  43. package/dist/repositories/members.js.map +1 -1
  44. package/dist/repositories/notifications.d.ts +23 -0
  45. package/dist/repositories/notifications.js +70 -0
  46. package/dist/repositories/notifications.js.map +1 -0
  47. package/dist/repositories/org-user-profile.d.ts +214 -1
  48. package/dist/repositories/org-user-profile.js +23 -2
  49. package/dist/repositories/org-user-profile.js.map +1 -1
  50. package/dist/repositories/organizations.d.ts +6 -7
  51. package/dist/repositories/organizations.js +45 -52
  52. package/dist/repositories/organizations.js.map +1 -1
  53. package/dist/repositories/outbox.js +3 -0
  54. package/dist/repositories/outbox.js.map +1 -1
  55. package/dist/repositories/pg-errors.d.ts +53 -5
  56. package/dist/repositories/pg-errors.js +99 -8
  57. package/dist/repositories/pg-errors.js.map +1 -1
  58. package/dist/repositories/posts.d.ts +39 -0
  59. package/dist/repositories/posts.js +255 -0
  60. package/dist/repositories/posts.js.map +1 -0
  61. package/dist/repositories/progress.d.ts +1 -1
  62. package/dist/repositories/progress.js +3 -0
  63. package/dist/repositories/progress.js.map +1 -1
  64. package/dist/repositories/settings.js +2 -0
  65. package/dist/repositories/settings.js.map +1 -1
  66. package/dist/schema/assets.d.ts +36 -2
  67. package/dist/schema/assets.js +12 -5
  68. package/dist/schema/assets.js.map +1 -1
  69. package/dist/schema/automations.d.ts +123 -8
  70. package/dist/schema/automations.js +11 -4
  71. package/dist/schema/automations.js.map +1 -1
  72. package/dist/schema/better-auth.d.ts +1613 -238
  73. package/dist/schema/better-auth.js +107 -22
  74. package/dist/schema/better-auth.js.map +1 -1
  75. package/dist/schema/content.d.ts +909 -22
  76. package/dist/schema/content.js +157 -13
  77. package/dist/schema/content.js.map +1 -1
  78. package/dist/schema/credentials.js +1 -1
  79. package/dist/schema/credentials.js.map +1 -1
  80. package/dist/schema/discussion.d.ts +2079 -55
  81. package/dist/schema/discussion.js +430 -13
  82. package/dist/schema/discussion.js.map +1 -1
  83. package/dist/schema/entitlements.d.ts +484 -2
  84. package/dist/schema/entitlements.js +121 -6
  85. package/dist/schema/entitlements.js.map +1 -1
  86. package/dist/schema/identity.d.ts +517 -1
  87. package/dist/schema/identity.js +118 -2
  88. package/dist/schema/identity.js.map +1 -1
  89. package/dist/schema/index.d.ts +6 -6
  90. package/dist/schema/index.js +32 -7
  91. package/dist/schema/index.js.map +1 -1
  92. package/dist/schema/integrations.js +1 -1
  93. package/dist/schema/integrations.js.map +1 -1
  94. package/dist/schema/organizations.d.ts +21 -4
  95. package/dist/schema/organizations.js +4 -1
  96. package/dist/schema/organizations.js.map +1 -1
  97. package/dist/schema/outbox.d.ts +17 -0
  98. package/dist/schema/outbox.js +1 -0
  99. package/dist/schema/outbox.js.map +1 -1
  100. package/dist/schema/progress.d.ts +17 -0
  101. package/dist/schema/progress.js +1 -0
  102. package/dist/schema/progress.js.map +1 -1
  103. package/dist/schema/settings.js.map +1 -1
  104. package/dist/unit-of-work.js +7 -2
  105. package/dist/unit-of-work.js.map +1 -1
  106. package/drizzle/0000_baseline.sql +0 -1
  107. package/drizzle/0001_new_sentry.sql +43 -0
  108. package/drizzle/0002_automation_kinds.sql +7 -0
  109. package/drizzle/0003_community.sql +340 -0
  110. package/drizzle/0004_assets_sources.sql +1 -0
  111. package/drizzle/0005_notices_and_seed_index.sql +12 -0
  112. package/drizzle/0006_community_review_fixes.sql +24 -0
  113. package/drizzle/0007_notifications.sql +37 -0
  114. package/drizzle/0008_content_access.sql +13 -0
  115. package/drizzle/0009_community_indexes.sql +56 -0
  116. package/drizzle/0010_mcp_access.sql +114 -0
  117. package/drizzle/meta/0000_snapshot.json +167 -597
  118. package/drizzle/meta/0001_snapshot.json +3769 -0
  119. package/drizzle/meta/0002_snapshot.json +3770 -0
  120. package/drizzle/meta/0003_snapshot.json +7061 -0
  121. package/drizzle/meta/0004_snapshot.json +7068 -0
  122. package/drizzle/meta/0005_snapshot.json +7180 -0
  123. package/drizzle/meta/0006_snapshot.json +7298 -0
  124. package/drizzle/meta/0007_snapshot.json +7620 -0
  125. package/drizzle/meta/0008_snapshot.json +7666 -0
  126. package/drizzle/meta/0009_snapshot.json +8185 -0
  127. package/drizzle/meta/0010_snapshot.json +8813 -0
  128. package/drizzle/meta/_journal.json +71 -1
  129. package/package.json +3 -2
  130. package/dist/repositories/dashboard.d.ts +0 -14
  131. package/dist/repositories/dashboard.js +0 -55
  132. package/dist/repositories/dashboard.js.map +0 -1
  133. package/dist/repositories/learn.d.ts +0 -19
  134. package/dist/repositories/learn.js +0 -54
  135. package/dist/repositories/learn.js.map +0 -1
  136. package/dist/repositories/students.d.ts +0 -15
  137. package/dist/repositories/students.js +0 -83
  138. package/dist/repositories/students.js.map +0 -1
@@ -1,18 +1,18 @@
1
1
  import { invites, orgUsers, organizations } from "./organizations.js";
2
- import { activities, activityAssets, contentItems, courses, downloadAssets, downloads, modules } from "./content.js";
3
- import { entitlements } from "./entitlements.js";
2
+ import { activities, activityAssets, bundleItems, bundles, communities, contentItems, courses, downloadAssets, downloads, modules, spaceLinks, spaceTopics, spaces } from "./content.js";
3
+ import { contentAccess, entitlementEndingSoonNotices, entitlementExpiryNotices, entitlements, spaceMembers } from "./entitlements.js";
4
4
  import { progressRecords } from "./progress.js";
5
- import { users } from "./identity.js";
5
+ import { notificationPreferences, notifications, userProfiles, users } from "./identity.js";
6
6
  import { assets } from "./assets.js";
7
7
  import { credentials } from "./credentials.js";
8
8
  import { connections } from "./integrations.js";
9
9
  import { eventOutbox } from "./outbox.js";
10
10
  import { automationRuns, automations } from "./automations.js";
11
11
  import { settings } from "./settings.js";
12
- import { commentReactions, commentReports, comments } from "./discussion.js";
12
+ import { blockedUsers, chatUsers, chats, commentFlags, commentReactions, comments, messageAttachments, messageFlags, messageReactions, messages, postBookmarks, postFlags, postFollows, postReactions, posts } from "./discussion.js";
13
13
  declare namespace index_d_exports {
14
- export { activities, activityAssets, assets, automationRuns, automations, commentReactions, commentReports, comments, connections, contentItems, courses, credentials, downloadAssets, downloads, entitlements, eventOutbox, invites, modules, orgUsers, organizations, progressRecords, settings, users };
14
+ export { activities, activityAssets, assets, automationRuns, automations, blockedUsers, bundleItems, bundles, chatUsers, chats, commentFlags, commentReactions, comments, communities, connections, contentAccess, contentItems, courses, credentials, downloadAssets, downloads, entitlementEndingSoonNotices, entitlementExpiryNotices, entitlements, eventOutbox, invites, messageAttachments, messageFlags, messageReactions, messages, modules, notificationPreferences, notifications, orgUsers, organizations, postBookmarks, postFlags, postFollows, postReactions, posts, progressRecords, settings, spaceLinks, spaceMembers, spaceTopics, spaces, userProfiles, users };
15
15
  }
16
16
  //#endregion
17
- export { activities, activityAssets, assets, automationRuns, automations, commentReactions, commentReports, comments, connections, contentItems, courses, credentials, downloadAssets, downloads, entitlements, eventOutbox, index_d_exports, invites, modules, orgUsers, organizations, progressRecords, settings, users };
17
+ export { activities, activityAssets, assets, automationRuns, automations, blockedUsers, bundleItems, bundles, chatUsers, chats, commentFlags, commentReactions, comments, communities, connections, contentAccess, contentItems, courses, credentials, downloadAssets, downloads, entitlementEndingSoonNotices, entitlementExpiryNotices, entitlements, eventOutbox, index_d_exports, invites, messageAttachments, messageFlags, messageReactions, messages, modules, notificationPreferences, notifications, orgUsers, organizations, postBookmarks, postFlags, postFollows, postReactions, posts, progressRecords, settings, spaceLinks, spaceMembers, spaceTopics, spaces, userProfiles, users };
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -1,16 +1,16 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
- import { users } from "./identity.js";
3
- import { invites, orgUsers, organizations } from "./organizations.js";
4
2
  import { assets } from "./assets.js";
5
- import { activities, activityAssets, contentItems, courses, downloadAssets, downloads, modules } from "./content.js";
6
- import { entitlements } from "./entitlements.js";
3
+ import { activities, activityAssets, bundleItems, bundles, communities, contentItems, courses, downloadAssets, downloads, modules, spaceLinks, spaceTopics, spaces } from "./content.js";
4
+ import { blockedUsers, chatUsers, chats, commentFlags, commentReactions, comments, messageAttachments, messageFlags, messageReactions, messages, postBookmarks, postFlags, postFollows, postReactions, posts } from "./discussion.js";
5
+ import { notificationPreferences, notifications, userProfiles, users } from "./identity.js";
6
+ import { invites, orgUsers, organizations } from "./organizations.js";
7
+ import { contentAccess, entitlementEndingSoonNotices, entitlementExpiryNotices, entitlements, spaceMembers } from "./entitlements.js";
7
8
  import { progressRecords } from "./progress.js";
8
9
  import { credentials } from "./credentials.js";
9
10
  import { connections } from "./integrations.js";
10
11
  import { eventOutbox } from "./outbox.js";
11
12
  import { automationRuns, automations } from "./automations.js";
12
13
  import { settings } from "./settings.js";
13
- import { commentReactions, commentReports, comments } from "./discussion.js";
14
14
  //#region src/schema/index.ts
15
15
  var schema_exports = /* @__PURE__ */ __exportAll({
16
16
  activities: () => activities,
@@ -18,26 +18,51 @@ var schema_exports = /* @__PURE__ */ __exportAll({
18
18
  assets: () => assets,
19
19
  automationRuns: () => automationRuns,
20
20
  automations: () => automations,
21
+ blockedUsers: () => blockedUsers,
22
+ bundleItems: () => bundleItems,
23
+ bundles: () => bundles,
24
+ chatUsers: () => chatUsers,
25
+ chats: () => chats,
26
+ commentFlags: () => commentFlags,
21
27
  commentReactions: () => commentReactions,
22
- commentReports: () => commentReports,
23
28
  comments: () => comments,
29
+ communities: () => communities,
24
30
  connections: () => connections,
31
+ contentAccess: () => contentAccess,
25
32
  contentItems: () => contentItems,
26
33
  courses: () => courses,
27
34
  credentials: () => credentials,
28
35
  downloadAssets: () => downloadAssets,
29
36
  downloads: () => downloads,
37
+ entitlementEndingSoonNotices: () => entitlementEndingSoonNotices,
38
+ entitlementExpiryNotices: () => entitlementExpiryNotices,
30
39
  entitlements: () => entitlements,
31
40
  eventOutbox: () => eventOutbox,
32
41
  invites: () => invites,
42
+ messageAttachments: () => messageAttachments,
43
+ messageFlags: () => messageFlags,
44
+ messageReactions: () => messageReactions,
45
+ messages: () => messages,
33
46
  modules: () => modules,
47
+ notificationPreferences: () => notificationPreferences,
48
+ notifications: () => notifications,
34
49
  orgUsers: () => orgUsers,
35
50
  organizations: () => organizations,
51
+ postBookmarks: () => postBookmarks,
52
+ postFlags: () => postFlags,
53
+ postFollows: () => postFollows,
54
+ postReactions: () => postReactions,
55
+ posts: () => posts,
36
56
  progressRecords: () => progressRecords,
37
57
  settings: () => settings,
58
+ spaceLinks: () => spaceLinks,
59
+ spaceMembers: () => spaceMembers,
60
+ spaceTopics: () => spaceTopics,
61
+ spaces: () => spaces,
62
+ userProfiles: () => userProfiles,
38
63
  users: () => users
39
64
  });
40
65
  //#endregion
41
- export { activities, activityAssets, assets, automationRuns, automations, commentReactions, commentReports, comments, connections, contentItems, courses, credentials, downloadAssets, downloads, entitlements, eventOutbox, invites, modules, orgUsers, organizations, progressRecords, schema_exports, settings, users };
66
+ export { activities, activityAssets, assets, automationRuns, automations, blockedUsers, bundleItems, bundles, chatUsers, chats, commentFlags, commentReactions, comments, communities, connections, contentAccess, contentItems, courses, credentials, downloadAssets, downloads, entitlementEndingSoonNotices, entitlementExpiryNotices, entitlements, eventOutbox, invites, messageAttachments, messageFlags, messageReactions, messages, modules, notificationPreferences, notifications, orgUsers, organizations, postBookmarks, postFlags, postFollows, postReactions, posts, progressRecords, schema_exports, settings, spaceLinks, spaceMembers, spaceTopics, spaces, userProfiles, users };
42
67
 
43
68
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/schema/index.ts"],"sourcesContent":["// Centralized Drizzle schema. All domain tables live here, grouped by the\n// bounded context that owns them. Re-exported so drizzle-kit and the\n// repositories have a single import surface.\nexport * from './organizations.js';\nexport * from './content.js';\nexport * from './entitlements.js';\nexport * from './progress.js';\nexport * from './identity.js';\nexport * from './assets.js';\nexport * from './credentials.js';\nexport * from './integrations.js';\nexport * from './outbox.js';\nexport * from './automations.js';\nexport * from './settings.js';\nexport * from './discussion.js';\n"],"mappings":""}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/schema/index.ts"],"sourcesContent":["// Centralized Drizzle schema. All domain tables live here, grouped by the\n// bounded context that owns them. Re-exported so drizzle-kit and the\n// repositories have a single import surface.\nexport * from \"./organizations.js\";\nexport * from \"./content.js\";\nexport * from \"./entitlements.js\";\nexport * from \"./progress.js\";\nexport * from \"./identity.js\";\nexport * from \"./assets.js\";\nexport * from \"./credentials.js\";\nexport * from \"./integrations.js\";\nexport * from \"./outbox.js\";\nexport * from \"./automations.js\";\nexport * from \"./settings.js\";\nexport * from \"./discussion.js\";\n"],"mappings":""}
@@ -10,7 +10,7 @@ const connections = pgTable("connections", {
10
10
  active: boolean("active").notNull().default(true),
11
11
  credentialRef: text("credential_ref").notNull(),
12
12
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
13
- updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
13
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date())
14
14
  }, (t) => ({
15
15
  pk: primaryKey({ columns: [t.orgId, t.id] }),
16
16
  onePerIntegration: unique().on(t.orgId, t.integrationId),
@@ -1 +1 @@
1
- {"version":3,"file":"integrations.js","names":[],"sources":["../../src/schema/integrations.ts"],"sourcesContent":["// integrations tables — an org's connections to external services. One\n// connection per integration per org; the secret itself lives in the\n// credentials table (secure credential store), referenced by credential_ref.\nimport {\n pgTable,\n text,\n boolean,\n jsonb,\n timestamp,\n primaryKey,\n foreignKey,\n unique,\n} from 'drizzle-orm/pg-core';\nimport type { Connection } from '@headless-lms/core/schemas';\nimport { organizations } from './organizations.js';\nimport { credentials } from './credentials.js';\nimport type { Expect, NoDrift } from './drift.js';\n\nexport const connections = pgTable(\n 'connections',\n {\n orgId: text('org_id')\n .notNull()\n .references(() => organizations.id),\n id: text('id').notNull(),\n integrationId: text('integration_id').notNull(),\n config: jsonb('config').$type<Connection['config']>().notNull().default({}),\n active: boolean('active').notNull().default(true),\n credentialRef: text('credential_ref').notNull(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n onePerIntegration: unique().on(t.orgId, t.integrationId),\n credentialFk: foreignKey({\n columns: [t.orgId, t.credentialRef],\n foreignColumns: [credentials.orgId, credentials.id],\n }),\n }),\n);\n\ntype _ConnectionsDrift = Expect<NoDrift<typeof connections.$inferSelect, Connection>>;\n"],"mappings":";;;;AAkBA,MAAa,cAAc,QACzB,eACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CAAC,QAAQ;CACvB,eAAe,KAAK,gBAAgB,CAAC,CAAC,QAAQ;CAC9C,QAAQ,MAAM,QAAQ,CAAC,CAAC,MAA4B,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC1E,QAAQ,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,IAAI;CAChD,eAAe,KAAK,gBAAgB,CAAC,CAAC,QAAQ;CAC9C,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;AAClF,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC3C,mBAAmB,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa;CACvD,cAAc,WAAW;EACvB,SAAS,CAAC,EAAE,OAAO,EAAE,aAAa;EAClC,gBAAgB,CAAC,YAAY,OAAO,YAAY,EAAE;CACpD,CAAC;AACH,EACF"}
1
+ {"version":3,"file":"integrations.js","names":[],"sources":["../../src/schema/integrations.ts"],"sourcesContent":["// integrations tables — an org's connections to external services. One\n// connection per integration per org; the secret itself lives in the\n// credentials table (secure credential store), referenced by credential_ref.\nimport {\n pgTable,\n text,\n boolean,\n jsonb,\n timestamp,\n primaryKey,\n foreignKey,\n unique,\n} from \"drizzle-orm/pg-core\";\nimport type { Connection } from \"@headless-lms/core/schemas\";\nimport { organizations } from \"./organizations.js\";\nimport { credentials } from \"./credentials.js\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const connections = pgTable(\n \"connections\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\").notNull(),\n integrationId: text(\"integration_id\").notNull(),\n config: jsonb(\"config\").$type<Connection[\"config\"]>().notNull().default({}),\n active: boolean(\"active\").notNull().default(true),\n credentialRef: text(\"credential_ref\").notNull(),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n onePerIntegration: unique().on(t.orgId, t.integrationId),\n credentialFk: foreignKey({\n columns: [t.orgId, t.credentialRef],\n foreignColumns: [credentials.orgId, credentials.id],\n }),\n }),\n);\n\ntype _ConnectionsDrift = Expect<NoDrift<typeof connections.$inferSelect, Connection>>;\n"],"mappings":";;;;AAkBA,MAAa,cAAc,QACzB,eACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CAAC,QAAQ;CACvB,eAAe,KAAK,gBAAgB,CAAC,CAAC,QAAQ;CAC9C,QAAQ,MAAM,QAAQ,CAAC,CAAC,MAA4B,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC1E,QAAQ,QAAQ,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,IAAI;CAChD,eAAe,KAAK,gBAAgB,CAAC,CAAC,QAAQ;CAC9C,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC3C,mBAAmB,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa;CACvD,cAAc,WAAW;EACvB,SAAS,CAAC,EAAE,OAAO,EAAE,aAAa;EAClC,gBAAgB,CAAC,YAAY,OAAO,YAAY,EAAE;CACpD,CAAC;AACH,EACF"}
@@ -185,14 +185,14 @@ declare const orgUsers: import("drizzle-orm/pg-core").PgTableWithColumns<{
185
185
  tableName: "org_users";
186
186
  dataType: "string";
187
187
  columnType: "PgText";
188
- data: "student" | "owner" | "admin" | "instructor";
188
+ data: "student" | "owner" | "admin" | "instructor" | "moderator";
189
189
  driverParam: string;
190
190
  notNull: true;
191
191
  hasDefault: false;
192
192
  isPrimaryKey: false;
193
193
  isAutoincrement: false;
194
194
  hasRuntimeDefault: false;
195
- enumValues: ["owner", "admin", "instructor", "student"];
195
+ enumValues: ["owner", "admin", "instructor", "moderator", "student"];
196
196
  baseColumn: never;
197
197
  identity: undefined;
198
198
  generated: undefined;
@@ -311,14 +311,14 @@ declare const invites: import("drizzle-orm/pg-core").PgTableWithColumns<{
311
311
  tableName: "invites";
312
312
  dataType: "string";
313
313
  columnType: "PgText";
314
- data: "student" | "admin" | "instructor";
314
+ data: "student" | "admin" | "instructor" | "moderator";
315
315
  driverParam: string;
316
316
  notNull: true;
317
317
  hasDefault: false;
318
318
  isPrimaryKey: false;
319
319
  isAutoincrement: false;
320
320
  hasRuntimeDefault: false;
321
- enumValues: ["admin", "instructor", "student"];
321
+ enumValues: ["admin", "instructor", "moderator", "student"];
322
322
  baseColumn: never;
323
323
  identity: undefined;
324
324
  generated: undefined;
@@ -408,6 +408,23 @@ declare const invites: import("drizzle-orm/pg-core").PgTableWithColumns<{
408
408
  identity: undefined;
409
409
  generated: undefined;
410
410
  }, {}, {}>;
411
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
412
+ name: "updated_at";
413
+ tableName: "invites";
414
+ dataType: "date";
415
+ columnType: "PgTimestamp";
416
+ data: Date;
417
+ driverParam: string;
418
+ notNull: true;
419
+ hasDefault: true;
420
+ isPrimaryKey: false;
421
+ isAutoincrement: false;
422
+ hasRuntimeDefault: false;
423
+ enumValues: undefined;
424
+ baseColumn: never;
425
+ identity: undefined;
426
+ generated: undefined;
427
+ }, {}, {}>;
411
428
  };
412
429
  dialect: "pg";
413
430
  }>;
@@ -20,6 +20,7 @@ const orgUsers = pgTable("org_users", {
20
20
  "owner",
21
21
  "admin",
22
22
  "instructor",
23
+ "moderator",
23
24
  "student"
24
25
  ] }).notNull(),
25
26
  status: text("status", { enum: ["invited", "active"] }).notNull().default("active"),
@@ -36,6 +37,7 @@ const invites = pgTable("invites", {
36
37
  role: text("role", { enum: [
37
38
  "admin",
38
39
  "instructor",
40
+ "moderator",
39
41
  "student"
40
42
  ] }).notNull(),
41
43
  status: text("status", { enum: [
@@ -47,7 +49,8 @@ const invites = pgTable("invites", {
47
49
  invitedBy: text("invited_by").notNull().references(() => users.id),
48
50
  tokenHash: text("token_hash").unique(),
49
51
  expiresAt: timestamp("expires_at", { withTimezone: true }),
50
- createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
52
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
53
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date())
51
54
  }, (t) => ({
52
55
  pk: primaryKey({ columns: [t.orgId, t.id] }),
53
56
  pendingEmailUq: uniqueIndex("invites_pending_email_uq").on(t.orgId, t.email).where(sql`${t.status} = 'pending'`)
@@ -1 +1 @@
1
- {"version":3,"file":"organizations.js","names":[],"sources":["../../src/schema/organizations.ts"],"sourcesContent":["import { sql } from 'drizzle-orm';\nimport {\n pgTable,\n text,\n timestamp,\n primaryKey,\n unique,\n uniqueIndex,\n} from 'drizzle-orm/pg-core';\nimport type { Invite, Organization, OrgUser } from '@headless-lms/core/schemas';\nimport { genId } from '@headless-lms/core/shared/id';\nimport { users } from './identity.js';\nimport type { Expect, NoDrift } from './drift.js';\n\nexport const organizations = pgTable('organizations', {\n id: text('id')\n .primaryKey()\n .$defaultFn(() => genId('organization')),\n // Links to the better-auth organization record.\n externalId: text('external_id').unique(),\n name: text('name').notNull(),\n slug: text('slug').notNull().unique(),\n ownerId: text('owner_id')\n .notNull()\n .references(() => users.id),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n});\n\n// A person's link to an organization under one role\nexport const orgUsers = pgTable(\n 'org_users',\n {\n orgId: text('org_id')\n .notNull()\n .references(() => organizations.id),\n id: text('id')\n .notNull()\n .$defaultFn(() => genId('orgUser')),\n\n userId: text('user_id')\n .notNull()\n .references(() => users.id),\n role: text('role', { enum: ['owner', 'admin', 'instructor', 'student'] }).notNull(),\n // 'invited' from the moment an admin adds a student until they accept.\n // Staff rows are mirrored from an auth member record that only exists once\n // they have joined, so they are created 'active'.\n status: text('status', { enum: ['invited', 'active'] })\n .notNull()\n .default('active'),\n\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n userUq: unique().on(t.orgId, t.userId),\n }),\n);\n\nexport const invites = pgTable(\n 'invites',\n {\n orgId: text('org_id')\n .notNull()\n .references(() => organizations.id),\n id: text('id')\n .notNull()\n .$defaultFn(() => genId('invite')),\n email: text('email').notNull(),\n role: text('role', { enum: ['admin', 'instructor', 'student'] }).notNull(),\n status: text('status', {\n enum: ['pending', 'accepted', 'rejected', 'canceled'],\n }).notNull(),\n invitedBy: text('invited_by')\n .notNull()\n .references(() => users.id),\n tokenHash: text('token_hash').unique(),\n expiresAt: timestamp('expires_at', { withTimezone: true }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n // One pending invite per (org, email) — the upsert's conflict target.\n pendingEmailUq: uniqueIndex('invites_pending_email_uq')\n .on(t.orgId, t.email)\n .where(sql`${t.status} = 'pending'`),\n }),\n);\n\ntype _OrganizationsDrift = Expect<NoDrift<typeof organizations.$inferSelect, Organization>>;\ntype _OrgUsersDrift = Expect<NoDrift<typeof orgUsers.$inferSelect, OrgUser>>;\ntype _InvitesDrift = Expect<NoDrift<typeof invites.$inferSelect, Invite>>;\n\n"],"mappings":";;;;;AAcA,MAAa,gBAAgB,QAAQ,iBAAiB;CACpD,IAAI,KAAK,IAAI,CAAC,CACX,WAAW,CAAC,CACZ,iBAAiB,MAAM,cAAc,CAAC;CAEzC,YAAY,KAAK,aAAa,CAAC,CAAC,OAAO;CACvC,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ;CAC3B,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO;CACpC,SAAS,KAAK,UAAU,CAAC,CACtB,QAAQ,CAAC,CACT,iBAAiB,MAAM,EAAE;CAC5B,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,CAAC;AAGD,MAAa,WAAW,QACtB,aACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,SAAS,CAAC;CAEpC,QAAQ,KAAK,SAAS,CAAC,CACpB,QAAQ,CAAC,CACT,iBAAiB,MAAM,EAAE;CAC5B,MAAM,KAAK,QAAQ,EAAE,MAAM;EAAC;EAAS;EAAS;EAAc;CAAS,EAAE,CAAC,CAAC,CAAC,QAAQ;CAIlF,QAAQ,KAAK,UAAU,EAAE,MAAM,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC,CACpD,QAAQ,CAAC,CACT,QAAQ,QAAQ;CAEnB,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC3C,QAAQ,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM;AACvC,EACF;AAEA,MAAa,UAAU,QACrB,WACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,QAAQ,CAAC;CACnC,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ;CAC7B,MAAM,KAAK,QAAQ,EAAE,MAAM;EAAC;EAAS;EAAc;CAAS,EAAE,CAAC,CAAC,CAAC,QAAQ;CACzE,QAAQ,KAAK,UAAU,EACrB,MAAM;EAAC;EAAW;EAAY;EAAY;CAAU,EACtD,CAAC,CAAC,CAAC,QAAQ;CACX,WAAW,KAAK,YAAY,CAAC,CAC1B,QAAQ,CAAC,CACT,iBAAiB,MAAM,EAAE;CAC5B,WAAW,KAAK,YAAY,CAAC,CAAC,OAAO;CACrC,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC;CACzD,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;AAClF,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAE3C,gBAAgB,YAAY,0BAA0B,CAAC,CACpD,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,CACpB,MAAM,GAAG,GAAG,EAAE,OAAO,aAAa;AACvC,EACF"}
1
+ {"version":3,"file":"organizations.js","names":[],"sources":["../../src/schema/organizations.ts"],"sourcesContent":["import { sql } from \"drizzle-orm\";\nimport { pgTable, text, timestamp, primaryKey, unique, uniqueIndex } from \"drizzle-orm/pg-core\";\nimport type { Invite, Organization, OrgUser } from \"@headless-lms/core/schemas\";\nimport { genId } from \"@headless-lms/core/shared/id\";\nimport { users } from \"./identity.js\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const organizations = pgTable(\"organizations\", {\n id: text(\"id\")\n .primaryKey()\n .$defaultFn(() => genId(\"organization\")),\n // Links to the better-auth organization record.\n externalId: text(\"external_id\").unique(),\n name: text(\"name\").notNull(),\n slug: text(\"slug\").notNull().unique(),\n ownerId: text(\"owner_id\")\n .notNull()\n .references(() => users.id),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n});\n\n// A person's link to an organization under one role\nexport const orgUsers = pgTable(\n \"org_users\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\")\n .notNull()\n .$defaultFn(() => genId(\"orgUser\")),\n\n userId: text(\"user_id\")\n .notNull()\n .references(() => users.id),\n role: text(\"role\", {\n enum: [\"owner\", \"admin\", \"instructor\", \"moderator\", \"student\"],\n }).notNull(),\n // 'invited' from the moment an admin adds a student until they accept.\n // Staff rows are mirrored from an auth member record that only exists once\n // they have joined, so they are created 'active'.\n status: text(\"status\", { enum: [\"invited\", \"active\"] })\n .notNull()\n .default(\"active\"),\n\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n userUq: unique().on(t.orgId, t.userId),\n }),\n);\n\nexport const invites = pgTable(\n \"invites\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\")\n .notNull()\n .$defaultFn(() => genId(\"invite\")),\n email: text(\"email\").notNull(),\n role: text(\"role\", { enum: [\"admin\", \"instructor\", \"moderator\", \"student\"] }).notNull(),\n status: text(\"status\", {\n enum: [\"pending\", \"accepted\", \"rejected\", \"canceled\"],\n }).notNull(),\n invitedBy: text(\"invited_by\")\n .notNull()\n .references(() => users.id),\n tokenHash: text(\"token_hash\").unique(),\n expiresAt: timestamp(\"expires_at\", { withTimezone: true }),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n // One pending invite per (org, email) — the upsert's conflict target.\n pendingEmailUq: uniqueIndex(\"invites_pending_email_uq\")\n .on(t.orgId, t.email)\n .where(sql`${t.status} = 'pending'`),\n }),\n);\n\ntype _OrganizationsDrift = Expect<NoDrift<typeof organizations.$inferSelect, Organization>>;\ntype _OrgUsersDrift = Expect<NoDrift<typeof orgUsers.$inferSelect, OrgUser>>;\ntype _InvitesDrift = Expect<NoDrift<typeof invites.$inferSelect, Invite>>;\n"],"mappings":";;;;;AAOA,MAAa,gBAAgB,QAAQ,iBAAiB;CACpD,IAAI,KAAK,IAAI,CAAC,CACX,WAAW,CAAC,CACZ,iBAAiB,MAAM,cAAc,CAAC;CAEzC,YAAY,KAAK,aAAa,CAAC,CAAC,OAAO;CACvC,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ;CAC3B,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO;CACpC,SAAS,KAAK,UAAU,CAAC,CACtB,QAAQ,CAAC,CACT,iBAAiB,MAAM,EAAE;CAC5B,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,CAAC;AAGD,MAAa,WAAW,QACtB,aACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,SAAS,CAAC;CAEpC,QAAQ,KAAK,SAAS,CAAC,CACpB,QAAQ,CAAC,CACT,iBAAiB,MAAM,EAAE;CAC5B,MAAM,KAAK,QAAQ,EACjB,MAAM;EAAC;EAAS;EAAS;EAAc;EAAa;CAAS,EAC/D,CAAC,CAAC,CAAC,QAAQ;CAIX,QAAQ,KAAK,UAAU,EAAE,MAAM,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC,CACpD,QAAQ,CAAC,CACT,QAAQ,QAAQ;CAEnB,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC3C,QAAQ,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM;AACvC,EACF;AAEA,MAAa,UAAU,QACrB,WACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,QAAQ,CAAC;CACnC,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ;CAC7B,MAAM,KAAK,QAAQ,EAAE,MAAM;EAAC;EAAS;EAAc;EAAa;CAAS,EAAE,CAAC,CAAC,CAAC,QAAQ;CACtF,QAAQ,KAAK,UAAU,EACrB,MAAM;EAAC;EAAW;EAAY;EAAY;CAAU,EACtD,CAAC,CAAC,CAAC,QAAQ;CACX,WAAW,KAAK,YAAY,CAAC,CAC1B,QAAQ,CAAC,CACT,iBAAiB,MAAM,EAAE;CAC5B,WAAW,KAAK,YAAY,CAAC,CAAC,OAAO;CACrC,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC;CACzD,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAE3C,gBAAgB,YAAY,0BAA0B,CAAC,CACpD,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,CACpB,MAAM,GAAG,GAAG,EAAE,OAAO,aAAa;AACvC,EACF"}
@@ -141,6 +141,23 @@ declare const eventOutbox: import("drizzle-orm/pg-core").PgTableWithColumns<{
141
141
  identity: undefined;
142
142
  generated: undefined;
143
143
  }, {}, {}>;
144
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
145
+ name: "updated_at";
146
+ tableName: "event_outbox";
147
+ dataType: "date";
148
+ columnType: "PgTimestamp";
149
+ data: Date;
150
+ driverParam: string;
151
+ notNull: true;
152
+ hasDefault: true;
153
+ isPrimaryKey: false;
154
+ isAutoincrement: false;
155
+ hasRuntimeDefault: false;
156
+ enumValues: undefined;
157
+ baseColumn: never;
158
+ identity: undefined;
159
+ generated: undefined;
160
+ }, {}, {}>;
144
161
  processedAt: import("drizzle-orm/pg-core").PgColumn<{
145
162
  name: "processed_at";
146
163
  tableName: "event_outbox";
@@ -11,6 +11,7 @@ const eventOutbox = pgTable("event_outbox", {
11
11
  nextAttemptAt: timestamp("next_attempt_at", { withTimezone: true }).notNull().defaultNow(),
12
12
  lastError: text("last_error"),
13
13
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
14
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date()),
14
15
  processedAt: timestamp("processed_at", { withTimezone: true })
15
16
  }, (t) => ({ pendingIdx: index("event_outbox_pending_idx").on(t.id).where(sql`${t.processedAt} is null`) }));
16
17
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"outbox.js","names":[],"sources":["../../src/schema/outbox.ts"],"sourcesContent":["import { index, integer, jsonb, pgTable, text, timestamp } from 'drizzle-orm/pg-core';\nimport { sql } from 'drizzle-orm';\nimport type { EventOutbox } from '@headless-lms/core/schemas';\nimport { genId } from '@headless-lms/core/shared/id';\nimport type { Expect, NoDrift } from './drift.js';\n\nexport const eventOutbox = pgTable(\n 'event_outbox',\n {\n orgId: text('org_id').notNull(),\n id: text('id')\n .primaryKey()\n .$defaultFn(() => genId('event')),\n type: text('type').notNull(),\n payload: jsonb('payload').$type<EventOutbox['payload']>().notNull(),\n attempts: integer('attempts').notNull().default(0),\n nextAttemptAt: timestamp('next_attempt_at', { withTimezone: true }).notNull().defaultNow(),\n lastError: text('last_error'),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n processedAt: timestamp('processed_at', { withTimezone: true }),\n },\n (t) => ({\n pendingIdx: index('event_outbox_pending_idx')\n .on(t.id)\n .where(sql`${t.processedAt} is null`),\n }),\n);\n\ntype _EventOutboxDrift = Expect<NoDrift<typeof eventOutbox.$inferSelect, EventOutbox>>;\n"],"mappings":";;;;AAMA,MAAa,cAAc,QACzB,gBACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAAC,QAAQ;CAC9B,IAAI,KAAK,IAAI,CAAC,CACX,WAAW,CAAC,CACZ,iBAAiB,MAAM,OAAO,CAAC;CAClC,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ;CAC3B,SAAS,MAAM,SAAS,CAAC,CAAC,MAA8B,CAAC,CAAC,QAAQ;CAClE,UAAU,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;CACjD,eAAe,UAAU,mBAAmB,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CACzF,WAAW,KAAK,YAAY;CAC5B,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,aAAa,UAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;AAC/D,IACC,OAAO,EACN,YAAY,MAAM,0BAA0B,CAAC,CAC1C,GAAG,EAAE,EAAE,CAAC,CACR,MAAM,GAAG,GAAG,EAAE,YAAY,SAAS,EACxC,EACF"}
1
+ {"version":3,"file":"outbox.js","names":[],"sources":["../../src/schema/outbox.ts"],"sourcesContent":["import { index, integer, jsonb, pgTable, text, timestamp } from \"drizzle-orm/pg-core\";\nimport { sql } from \"drizzle-orm\";\nimport type { EventOutbox } from \"@headless-lms/core/schemas\";\nimport { genId } from \"@headless-lms/core/shared/id\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const eventOutbox = pgTable(\n \"event_outbox\",\n {\n orgId: text(\"org_id\").notNull(),\n id: text(\"id\")\n .primaryKey()\n .$defaultFn(() => genId(\"event\")),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").$type<EventOutbox[\"payload\"]>().notNull(),\n attempts: integer(\"attempts\").notNull().default(0),\n nextAttemptAt: timestamp(\"next_attempt_at\", { withTimezone: true }).notNull().defaultNow(),\n lastError: text(\"last_error\"),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n processedAt: timestamp(\"processed_at\", { withTimezone: true }),\n },\n (t) => ({\n pendingIdx: index(\"event_outbox_pending_idx\")\n .on(t.id)\n .where(sql`${t.processedAt} is null`),\n }),\n);\n\ntype _EventOutboxDrift = Expect<NoDrift<typeof eventOutbox.$inferSelect, EventOutbox>>;\n"],"mappings":";;;;AAMA,MAAa,cAAc,QACzB,gBACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAAC,QAAQ;CAC9B,IAAI,KAAK,IAAI,CAAC,CACX,WAAW,CAAC,CACZ,iBAAiB,MAAM,OAAO,CAAC;CAClC,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ;CAC3B,SAAS,MAAM,SAAS,CAAC,CAAC,MAA8B,CAAC,CAAC,QAAQ;CAClE,UAAU,QAAQ,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;CACjD,eAAe,UAAU,mBAAmB,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CACzF,WAAW,KAAK,YAAY;CAC5B,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;CAC7B,aAAa,UAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;AAC/D,IACC,OAAO,EACN,YAAY,MAAM,0BAA0B,CAAC,CAC1C,GAAG,EAAE,EAAE,CAAC,CACR,MAAM,GAAG,GAAG,EAAE,YAAY,SAAS,EACxC,EACF"}
@@ -141,6 +141,23 @@ declare const progressRecords: import("drizzle-orm/pg-core").PgTableWithColumns<
141
141
  identity: undefined;
142
142
  generated: undefined;
143
143
  }, {}, {}>;
144
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
145
+ name: "created_at";
146
+ tableName: "progress_records";
147
+ dataType: "date";
148
+ columnType: "PgTimestamp";
149
+ data: Date;
150
+ driverParam: string;
151
+ notNull: true;
152
+ hasDefault: true;
153
+ isPrimaryKey: false;
154
+ isAutoincrement: false;
155
+ hasRuntimeDefault: false;
156
+ enumValues: undefined;
157
+ baseColumn: never;
158
+ identity: undefined;
159
+ generated: undefined;
160
+ }, {}, {}>;
144
161
  updatedAt: import("drizzle-orm/pg-core").PgColumn<{
145
162
  name: "updated_at";
146
163
  tableName: "progress_records";
@@ -15,6 +15,7 @@ const progressRecords = pgTable("progress_records", {
15
15
  startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
16
16
  position: jsonb("position").$type(),
17
17
  completedAt: timestamp("completed_at", { withTimezone: true }),
18
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
18
19
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date())
19
20
  }, (t) => ({
20
21
  pk: primaryKey({ columns: [t.orgId, t.id] }),
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","names":[],"sources":["../../src/schema/progress.ts"],"sourcesContent":["// progress tables — one progress record per org user per target (activity,\n// module, or course). Tracks lifecycle: started_at on open, position\n// (typed resume payload) as the player reports it, completed_at when the rule is\n// satisfied (null = in progress). Target is denormalized (type + id, no FK) so a\n// record survives structure edits. Percentage and resume are derived on read;\n// nothing here is a stored percentage.\nimport {\n pgTable,\n text,\n jsonb,\n timestamp,\n primaryKey,\n unique,\n foreignKey,\n} from 'drizzle-orm/pg-core';\nimport type { ProgressRecord } from '@headless-lms/core/schemas';\nimport { genId } from '@headless-lms/core/shared/id';\nimport { organizations, orgUsers } from './organizations.js';\nimport type { Expect, NoDrift } from './drift.js';\n\nexport const progressRecords = pgTable(\n 'progress_records',\n {\n orgId: text('org_id')\n .notNull()\n .references(() => organizations.id),\n id: text('id')\n .notNull()\n .$defaultFn(() => genId('progress')),\n orgUserId: text('org_user_id').notNull(),\n targetType: text('target_type', {\n enum: ['activity', 'module', 'course'],\n }).notNull(),\n targetId: text('target_id').notNull(),\n startedAt: timestamp('started_at', { withTimezone: true }).notNull().defaultNow(),\n position: jsonb('position').$type<ProgressRecord['position']>(), // opaque typed payload; service interprets per target type\n completedAt: timestamp('completed_at', { withTimezone: true }), // null = in progress\n updatedAt: timestamp('updated_at', { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n targetUq: unique().on(t.orgId, t.orgUserId, t.targetType, t.targetId),\n // The one org user reference the schema previously left unenforced.\n orgUserFk: foreignKey({\n columns: [t.orgId, t.orgUserId],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }),\n }),\n);\n\ntype _ProgressRecordsDrift = Expect<NoDrift<typeof progressRecords.$inferSelect, ProgressRecord>>;\n"],"mappings":";;;;AAoBA,MAAa,kBAAkB,QAC7B,oBACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,UAAU,CAAC;CACrC,WAAW,KAAK,aAAa,CAAC,CAAC,QAAQ;CACvC,YAAY,KAAK,eAAe,EAC9B,MAAM;EAAC;EAAY;EAAU;CAAQ,EACvC,CAAC,CAAC,CAAC,QAAQ;CACX,UAAU,KAAK,WAAW,CAAC,CAAC,QAAQ;CACpC,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,UAAU,MAAM,UAAU,CAAC,CAAC,MAAkC;CAC9D,aAAa,UAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;CAC7D,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC3C,UAAU,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ;CAEpE,WAAW,WAAW;EACpB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS;EAC9B,gBAAgB,CAAC,SAAS,OAAO,SAAS,EAAE;CAC9C,CAAC;AACH,EACF"}
1
+ {"version":3,"file":"progress.js","names":[],"sources":["../../src/schema/progress.ts"],"sourcesContent":["// progress tables — one progress record per org user per target (activity,\n// module, or course). Tracks lifecycle: started_at on open, position\n// (typed resume payload) as the player reports it, completed_at when the rule is\n// satisfied (null = in progress). Target is denormalized (type + id, no FK) so a\n// record survives structure edits. Percentage and resume are derived on read;\n// nothing here is a stored percentage.\nimport {\n pgTable,\n text,\n jsonb,\n timestamp,\n primaryKey,\n unique,\n foreignKey,\n} from \"drizzle-orm/pg-core\";\nimport type { ProgressRecord } from \"@headless-lms/core/schemas\";\nimport { genId } from \"@headless-lms/core/shared/id\";\nimport { organizations, orgUsers } from \"./organizations.js\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const progressRecords = pgTable(\n \"progress_records\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\")\n .notNull()\n .$defaultFn(() => genId(\"progress\")),\n orgUserId: text(\"org_user_id\").notNull(),\n targetType: text(\"target_type\", {\n enum: [\"activity\", \"module\", \"course\"],\n }).notNull(),\n targetId: text(\"target_id\").notNull(),\n startedAt: timestamp(\"started_at\", { withTimezone: true }).notNull().defaultNow(),\n position: jsonb(\"position\").$type<ProgressRecord[\"position\"]>(), // opaque typed payload; service interprets per target type\n completedAt: timestamp(\"completed_at\", { withTimezone: true }), // null = in progress\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.id] }),\n targetUq: unique().on(t.orgId, t.orgUserId, t.targetType, t.targetId),\n // The one org user reference the schema previously left unenforced.\n orgUserFk: foreignKey({\n columns: [t.orgId, t.orgUserId],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }),\n }),\n);\n\ntype _ProgressRecordsDrift = Expect<NoDrift<typeof progressRecords.$inferSelect, ProgressRecord>>;\n"],"mappings":";;;;AAoBA,MAAa,kBAAkB,QAC7B,oBACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,UAAU,CAAC;CACrC,WAAW,KAAK,aAAa,CAAC,CAAC,QAAQ;CACvC,YAAY,KAAK,eAAe,EAC9B,MAAM;EAAC;EAAY;EAAU;CAAQ,EACvC,CAAC,CAAC,CAAC,QAAQ;CACX,UAAU,KAAK,WAAW,CAAC,CAAC,QAAQ;CACpC,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,UAAU,MAAM,UAAU,CAAC,CAAC,MAAkC;CAC9D,aAAa,UAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;CAC7D,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO;CACN,IAAI,WAAW,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;CAC3C,UAAU,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ;CAEpE,WAAW,WAAW;EACpB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS;EAC9B,gBAAgB,CAAC,SAAS,OAAO,SAAS,EAAE;CAC9C,CAAC;AACH,EACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","names":[],"sources":["../../src/schema/settings.ts"],"sourcesContent":["// settings — cross-cutting configuration store. One row per\n// (org, namespace, scope): the namespace names the domain that owns and\n// interprets the values; the scope is the id the settings attach to (an org id\n// for org-wide defaults, otherwise any entity id — a course, an activity, …).\n//\n// Deliberately NOT bound to any domain: no FK to content or anywhere else, so\n// settings never learns what it is scoping. Rows orphaned by a deleted entity\n// are purged off that domain's *.deleted event, not by cascade.\nimport { pgTable, text, jsonb, timestamp, primaryKey } from 'drizzle-orm/pg-core';\nimport type { Setting } from '@headless-lms/core/schemas';\nimport { organizations } from './organizations.js';\nimport type { Expect, NoDrift } from './drift.js';\n\nexport const settings = pgTable(\n 'settings',\n {\n orgId: text('org_id')\n .notNull()\n .references(() => organizations.id),\n // The owning domain: 'content', 'discussion', … Values are validated and\n // interpreted by that domain, never here.\n namespace: text('namespace').notNull(),\n // Org-scoped rows carry the org id, so the column is never null and the\n // natural key can be the primary key.\n scopeId: text('scope_id').notNull(),\n value: jsonb('value').$type<Setting['value']>().notNull().default({}),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.namespace, t.scopeId] }),\n }),\n);\n\ntype _SettingsDrift = Expect<NoDrift<typeof settings.$inferSelect, Setting>>;\n"],"mappings":";;;AAaA,MAAa,WAAW,QACtB,YACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CAGpC,WAAW,KAAK,WAAW,CAAC,CAAC,QAAQ;CAGrC,SAAS,KAAK,UAAU,CAAC,CAAC,QAAQ;CAClC,OAAO,MAAM,OAAO,CAAC,CAAC,MAAwB,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;CACpE,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO,EACN,IAAI,WAAW,EAAE,SAAS;CAAC,EAAE;CAAO,EAAE;CAAW,EAAE;AAAO,EAAE,CAAC,EAC/D,EACF"}
1
+ {"version":3,"file":"settings.js","names":[],"sources":["../../src/schema/settings.ts"],"sourcesContent":["// settings — cross-cutting configuration store. One row per\n// (org, namespace, scope): the namespace names the domain that owns and\n// interprets the values; the scope is the id the settings attach to (an org id\n// for org-wide defaults, otherwise any entity id — a course, an activity, …).\n//\n// Deliberately NOT bound to any domain: no FK to content or anywhere else, so\n// settings never learns what it is scoping. Rows orphaned by a deleted entity\n// are purged off that domain's *.deleted event, not by cascade.\nimport { pgTable, text, jsonb, timestamp, primaryKey } from \"drizzle-orm/pg-core\";\nimport type { Setting } from \"@headless-lms/core/schemas\";\nimport { organizations } from \"./organizations.js\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const settings = pgTable(\n \"settings\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n // The owning domain: 'content', 'discussion', … Values are validated and\n // interpreted by that domain, never here.\n namespace: text(\"namespace\").notNull(),\n // Org-scoped rows carry the org id, so the column is never null and the\n // natural key can be the primary key.\n scopeId: text(\"scope_id\").notNull(),\n value: jsonb(\"value\").$type<Setting[\"value\"]>().notNull().default({}),\n createdAt: timestamp(\"created_at\", { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true })\n .notNull()\n .defaultNow()\n .$onUpdate(() => new Date()),\n },\n (t) => ({\n pk: primaryKey({ columns: [t.orgId, t.namespace, t.scopeId] }),\n }),\n);\n\ntype _SettingsDrift = Expect<NoDrift<typeof settings.$inferSelect, Setting>>;\n"],"mappings":";;;AAaA,MAAa,WAAW,QACtB,YACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CAGpC,WAAW,KAAK,WAAW,CAAC,CAAC,QAAQ;CAGrC,SAAS,KAAK,UAAU,CAAC,CAAC,QAAQ;CAClC,OAAO,MAAM,OAAO,CAAC,CAAC,MAAwB,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;CACpE,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CACvD,QAAQ,CAAC,CACT,WAAW,CAAC,CACZ,gCAAgB,IAAI,KAAK,CAAC;AAC/B,IACC,OAAO,EACN,IAAI,WAAW,EAAE,SAAS;CAAC,EAAE;CAAO,EAAE;CAAW,EAAE;AAAO,EAAE,CAAC,EAC/D,EACF"}
@@ -1,3 +1,4 @@
1
+ import { translateDbError } from "./repositories/pg-errors.js";
1
2
  //#region src/unit-of-work.ts
2
3
  var DrizzleUnitOfWork = class {
3
4
  db;
@@ -6,8 +7,12 @@ var DrizzleUnitOfWork = class {
6
7
  this.db = db;
7
8
  this.makeScope = makeScope;
8
9
  }
9
- run(fn) {
10
- return this.db.transaction((tx) => fn(this.makeScope(tx)));
10
+ async run(fn) {
11
+ try {
12
+ return await this.db.transaction((tx) => fn(this.makeScope(tx)));
13
+ } catch (err) {
14
+ throw translateDbError(err);
15
+ }
11
16
  }
12
17
  };
13
18
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"unit-of-work.js","names":[],"sources":["../src/unit-of-work.ts"],"sourcesContent":["import type { NodePgDatabase } from 'drizzle-orm/node-postgres';\nimport type { UnitOfWork } from '@headless-lms/core/shared/ports';\nimport type { Tx } from './client.js';\n\nexport class DrizzleUnitOfWork<Scope> implements UnitOfWork<Scope> {\n constructor(\n private readonly db: NodePgDatabase,\n private readonly makeScope: (tx: Tx) => Scope,\n ) {}\n\n run<T>(fn: (scope: Scope) => Promise<T>): Promise<T> {\n return this.db.transaction((tx) => fn(this.makeScope(tx)));\n }\n}\n"],"mappings":";AAIA,IAAa,oBAAb,MAAmE;CAE9C;CACA;CAFnB,YACE,IACA,WACA;EAFiB,KAAA,KAAA;EACA,KAAA,YAAA;CAChB;CAEH,IAAO,IAA8C;EACnD,OAAO,KAAK,GAAG,aAAa,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC,CAAC;CAC3D;AACF"}
1
+ {"version":3,"file":"unit-of-work.js","names":[],"sources":["../src/unit-of-work.ts"],"sourcesContent":["import type { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport type { UnitOfWork } from \"@headless-lms/core/shared/ports\";\nimport type { Tx } from \"./client.js\";\nimport { translateDbError } from \"./repositories/pg-errors.js\";\n\nexport class DrizzleUnitOfWork<Scope> implements UnitOfWork<Scope> {\n constructor(\n private readonly db: NodePgDatabase,\n private readonly makeScope: (tx: Tx) => Scope,\n ) {}\n\n async run<T>(fn: (scope: Scope) => Promise<T>): Promise<T> {\n try {\n return await this.db.transaction((tx) => fn(this.makeScope(tx)));\n } catch (err) {\n throw translateDbError(err);\n }\n }\n}\n"],"mappings":";;AAKA,IAAa,oBAAb,MAAmE;CAE9C;CACA;CAFnB,YACE,IACA,WACA;EAFiB,KAAA,KAAA;EACA,KAAA,YAAA;CAChB;CAEH,MAAM,IAAO,IAA8C;EACzD,IAAI;GACF,OAAO,MAAM,KAAK,GAAG,aAAa,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC,CAAC;EACjE,SAAS,KAAK;GACZ,MAAM,iBAAiB,GAAG;EAC5B;CACF;AACF"}
@@ -79,7 +79,6 @@ CREATE TABLE "courses" (
79
79
  "status" text DEFAULT 'draft' NOT NULL,
80
80
  "category" text DEFAULT '' NOT NULL,
81
81
  "thumbnail_asset_id" text,
82
- "settings" jsonb DEFAULT '{}'::jsonb NOT NULL,
83
82
  "created_at" timestamp with time zone DEFAULT now() NOT NULL,
84
83
  "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
85
84
  CONSTRAINT "courses_org_id_id_pk" PRIMARY KEY("org_id","id"),
@@ -0,0 +1,43 @@
1
+ CREATE TABLE "bundle_items" (
2
+ "org_id" text NOT NULL,
3
+ "bundle_id" text NOT NULL,
4
+ "content_id" text NOT NULL,
5
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
6
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
7
+ CONSTRAINT "bundle_items_org_id_bundle_id_content_id_pk" PRIMARY KEY("org_id","bundle_id","content_id")
8
+ );
9
+ --> statement-breakpoint
10
+ CREATE TABLE "bundles" (
11
+ "org_id" text NOT NULL,
12
+ "id" text NOT NULL,
13
+ "name" text NOT NULL,
14
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
15
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
16
+ CONSTRAINT "bundles_org_id_id_pk" PRIMARY KEY("org_id","id"),
17
+ CONSTRAINT "bundles_org_id_id_name_unique" UNIQUE("org_id","id","name")
18
+ );
19
+ --> statement-breakpoint
20
+ ALTER TABLE "entitlements" ALTER COLUMN "content_id" DROP NOT NULL;--> statement-breakpoint
21
+ ALTER TABLE "invites" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
22
+ ALTER TABLE "activity_assets" ADD COLUMN "created_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
23
+ ALTER TABLE "activity_assets" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
24
+ ALTER TABLE "content_items" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
25
+ ALTER TABLE "download_assets" ADD COLUMN "created_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
26
+ ALTER TABLE "download_assets" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
27
+ ALTER TABLE "entitlements" ADD COLUMN "bundle_id" text;--> statement-breakpoint
28
+ ALTER TABLE "entitlements" ADD COLUMN "created_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
29
+ ALTER TABLE "entitlements" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
30
+ ALTER TABLE "progress_records" ADD COLUMN "created_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
31
+ ALTER TABLE "assets" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
32
+ ALTER TABLE "event_outbox" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
33
+ ALTER TABLE "automation_runs" ADD COLUMN "created_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
34
+ ALTER TABLE "automation_runs" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
35
+ ALTER TABLE "comment_reactions" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
36
+ ALTER TABLE "comment_reports" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint
37
+ ALTER TABLE "bundle_items" ADD CONSTRAINT "bundle_items_org_id_organizations_id_fk" FOREIGN KEY ("org_id") REFERENCES "public"."organizations"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
38
+ ALTER TABLE "bundle_items" ADD CONSTRAINT "bundle_items_org_id_content_id_content_items_org_id_id_fk" FOREIGN KEY ("org_id","content_id") REFERENCES "public"."content_items"("org_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
39
+ ALTER TABLE "bundle_items" ADD CONSTRAINT "bundle_items_org_id_bundle_id_bundles_org_id_id_fk" FOREIGN KEY ("org_id","bundle_id") REFERENCES "public"."bundles"("org_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
40
+ ALTER TABLE "bundles" ADD CONSTRAINT "bundles_org_id_organizations_id_fk" FOREIGN KEY ("org_id") REFERENCES "public"."organizations"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
41
+ ALTER TABLE "entitlements" ADD CONSTRAINT "entitlements_org_id_bundle_id_bundles_org_id_id_fk" FOREIGN KEY ("org_id","bundle_id") REFERENCES "public"."bundles"("org_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
42
+ ALTER TABLE "entitlements" ADD CONSTRAINT "entitlements_org_id_org_user_id_bundle_id_unique" UNIQUE("org_id","org_user_id","bundle_id");--> statement-breakpoint
43
+ ALTER TABLE "entitlements" ADD CONSTRAINT "entitlements_target_check" CHECK (num_nonnulls("entitlements"."bundle_id", "entitlements"."content_id") = 1);
@@ -0,0 +1,7 @@
1
+ DROP INDEX "automations_org_trigger_idx";--> statement-breakpoint
2
+ ALTER TABLE "automations" ADD COLUMN "kind" text DEFAULT 'workflow' NOT NULL;--> statement-breakpoint
3
+ ALTER TABLE "automations" ADD COLUMN "triggers" text[];--> statement-breakpoint
4
+ UPDATE "automations" SET "triggers" = ARRAY["trigger"];--> statement-breakpoint
5
+ ALTER TABLE "automations" ALTER COLUMN "triggers" SET NOT NULL;--> statement-breakpoint
6
+ ALTER TABLE "automations" DROP COLUMN "trigger";--> statement-breakpoint
7
+ CREATE INDEX "automations_triggers_idx" ON "automations" USING gin ("triggers");