@headless-lms/adapter-db 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/migrate.js.map +1 -1
- package/dist/repositories/assets.d.ts +1 -1
- package/dist/repositories/assets.js +4 -1
- package/dist/repositories/assets.js.map +1 -1
- package/dist/repositories/automations.d.ts +7 -5
- package/dist/repositories/automations.js +35 -10
- package/dist/repositories/automations.js.map +1 -1
- package/dist/repositories/content.d.ts +21 -7
- package/dist/repositories/content.js +168 -18
- package/dist/repositories/content.js.map +1 -1
- package/dist/repositories/course-analytics.d.ts +15 -0
- package/dist/repositories/course-analytics.js +137 -0
- package/dist/repositories/course-analytics.js.map +1 -0
- package/dist/repositories/credentials.js +2 -0
- package/dist/repositories/credentials.js.map +1 -1
- package/dist/repositories/dashboard.js +2 -0
- package/dist/repositories/dashboard.js.map +1 -1
- package/dist/repositories/discussion.d.ts +1 -1
- package/dist/repositories/discussion.js +2 -0
- package/dist/repositories/discussion.js.map +1 -1
- package/dist/repositories/entitlements.d.ts +11 -5
- package/dist/repositories/entitlements.js +42 -17
- package/dist/repositories/entitlements.js.map +1 -1
- package/dist/repositories/identity.js +2 -0
- package/dist/repositories/identity.js.map +1 -1
- package/dist/repositories/integrations.d.ts +1 -1
- package/dist/repositories/integrations.js +2 -0
- package/dist/repositories/integrations.js.map +1 -1
- package/dist/repositories/learn.js +6 -4
- package/dist/repositories/learn.js.map +1 -1
- package/dist/repositories/members.js +2 -0
- package/dist/repositories/members.js.map +1 -1
- package/dist/repositories/org-user-profile.js.map +1 -1
- package/dist/repositories/organizations.d.ts +4 -6
- package/dist/repositories/organizations.js +26 -45
- package/dist/repositories/organizations.js.map +1 -1
- package/dist/repositories/outbox.js +3 -0
- package/dist/repositories/outbox.js.map +1 -1
- package/dist/repositories/pg-errors.d.ts +53 -5
- package/dist/repositories/pg-errors.js +97 -8
- package/dist/repositories/pg-errors.js.map +1 -1
- package/dist/repositories/progress.d.ts +1 -1
- package/dist/repositories/progress.js +3 -0
- package/dist/repositories/progress.js.map +1 -1
- package/dist/repositories/settings.js +2 -0
- package/dist/repositories/settings.js.map +1 -1
- package/dist/repositories/students.d.ts +2 -1
- package/dist/repositories/students.js +80 -3
- package/dist/repositories/students.js.map +1 -1
- package/dist/schema/assets.d.ts +17 -0
- package/dist/schema/assets.js +2 -1
- package/dist/schema/assets.js.map +1 -1
- package/dist/schema/automations.d.ts +85 -8
- package/dist/schema/automations.js +7 -4
- package/dist/schema/automations.js.map +1 -1
- package/dist/schema/better-auth.js.map +1 -1
- package/dist/schema/content.d.ts +272 -22
- package/dist/schema/content.js +40 -5
- package/dist/schema/content.js.map +1 -1
- package/dist/schema/credentials.js +1 -1
- package/dist/schema/credentials.js.map +1 -1
- package/dist/schema/discussion.d.ts +34 -0
- package/dist/schema/discussion.js +4 -2
- package/dist/schema/discussion.js.map +1 -1
- package/dist/schema/entitlements.d.ts +52 -1
- package/dist/schema/entitlements.js +15 -5
- package/dist/schema/entitlements.js.map +1 -1
- package/dist/schema/identity.js.map +1 -1
- package/dist/schema/index.d.ts +3 -3
- package/dist/schema/index.js +4 -2
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/integrations.js +1 -1
- package/dist/schema/integrations.js.map +1 -1
- package/dist/schema/organizations.d.ts +17 -0
- package/dist/schema/organizations.js +2 -1
- package/dist/schema/organizations.js.map +1 -1
- package/dist/schema/outbox.d.ts +17 -0
- package/dist/schema/outbox.js +1 -0
- package/dist/schema/outbox.js.map +1 -1
- package/dist/schema/progress.d.ts +17 -0
- package/dist/schema/progress.js +1 -0
- package/dist/schema/progress.js.map +1 -1
- package/dist/schema/settings.js.map +1 -1
- package/dist/unit-of-work.js +7 -2
- package/dist/unit-of-work.js.map +1 -1
- package/drizzle/0000_baseline.sql +0 -1
- package/drizzle/0001_new_sentry.sql +43 -0
- package/drizzle/0002_automation_kinds.sql +7 -0
- package/drizzle/meta/0000_snapshot.json +167 -597
- package/drizzle/meta/0001_snapshot.json +3769 -0
- package/drizzle/meta/0002_snapshot.json +3770 -0
- package/drizzle/meta/_journal.json +16 -2
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discussion.js","names":[],"sources":["../../src/schema/discussion.ts"],"sourcesContent":["// discussion tables — comments on an activity, their reactions and reports.\n// Configuration is not here: the course's comment settings ride on the course's\n// `content` settings row, and an activity's override rides on the activity's\n// own settings blob.\n//\n// The author is always an org user, so one column covers both\n// learners and staff. Staff-ness is NOT stored — it is read from the author's\n// current role. A removed comment keeps its row so replies below it survive;\n// only the body stops being served.\n//\n// No course_id: which course an activity sits in is content's fact and changes\n// when a course is restructured. The staff comment list joins to modules to\n// scope by course.\nimport {\n pgTable,\n text,\n timestamp,\n primaryKey,\n foreignKey,\n unique,\n index,\n check,\n} from
|
|
1
|
+
{"version":3,"file":"discussion.js","names":[],"sources":["../../src/schema/discussion.ts"],"sourcesContent":["// discussion tables — comments on an activity, their reactions and reports.\n// Configuration is not here: the course's comment settings ride on the course's\n// `content` settings row, and an activity's override rides on the activity's\n// own settings blob.\n//\n// The author is always an org user, so one column covers both\n// learners and staff. Staff-ness is NOT stored — it is read from the author's\n// current role. A removed comment keeps its row so replies below it survive;\n// only the body stops being served.\n//\n// No course_id: which course an activity sits in is content's fact and changes\n// when a course is restructured. The staff comment list joins to modules to\n// scope by course.\nimport {\n pgTable,\n text,\n timestamp,\n primaryKey,\n foreignKey,\n unique,\n index,\n check,\n} from \"drizzle-orm/pg-core\";\nimport { sql } from \"drizzle-orm\";\nimport type { Comment, CommentReaction, CommentReport } from \"@headless-lms/core/schemas\";\nimport { genId } from \"@headless-lms/core/shared/id\";\nimport { organizations, orgUsers } from \"./organizations.js\";\nimport { activities } from \"./content.js\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const comments = pgTable(\n \"comments\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\")\n .notNull()\n .$defaultFn(() => genId(\"comment\")),\n activityId: text(\"activity_id\").notNull(),\n parentId: text(\"parent_id\"),\n orgUserId: text(\"org_user_id\").notNull(),\n body: text(\"body\").notNull(),\n status: text(\"status\", { enum: [\"pending\", \"published\", \"removed\"] })\n .notNull()\n .default(\"published\"),\n removedBy: text(\"removed_by\"),\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 // Removing an activity removes its discussion (spec, boundary 1).\n activityFk: foreignKey({\n columns: [t.orgId, t.activityId],\n foreignColumns: [activities.orgId, activities.id],\n }).onDelete(\"cascade\"),\n authorFk: foreignKey({\n columns: [t.orgId, t.orgUserId],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }),\n removedByFk: foreignKey({\n columns: [t.orgId, t.removedBy],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }),\n // No cascade: removing a parent must not delete its replies.\n parentFk: foreignKey({\n columns: [t.orgId, t.parentId],\n foreignColumns: [t.orgId, t.id],\n }),\n // removed_by is set if and only if the comment is removed.\n removedCk: check(\n \"comments_removed_by_check\",\n sql`(${t.status} = 'removed') = (${t.removedBy} is not null)`,\n ),\n activityIdx: index(\"comments_activity_idx\").on(t.orgId, t.activityId, t.status, t.createdAt),\n // The staff list filters by status org-wide, then narrows by course through\n // the activity join — so the index leads on status, not on a stored course.\n queueIdx: index(\"comments_queue_idx\").on(t.orgId, t.status, t.createdAt),\n }),\n);\n\nexport const commentReactions = pgTable(\n \"comment_reactions\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n commentId: text(\"comment_id\").notNull(),\n orgUserId: text(\"org_user_id\").notNull(),\n emoji: text(\"emoji\").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 // One reaction per person, per comment.\n pk: primaryKey({ columns: [t.orgId, t.commentId, t.orgUserId] }),\n commentFk: foreignKey({\n columns: [t.orgId, t.commentId],\n foreignColumns: [comments.orgId, comments.id],\n }).onDelete(\"cascade\"),\n authorFk: foreignKey({\n columns: [t.orgId, t.orgUserId],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }),\n }),\n);\n\nexport const commentReports = pgTable(\n \"comment_reports\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\")\n .notNull()\n .$defaultFn(() => genId(\"commentReport\")),\n commentId: text(\"comment_id\").notNull(),\n orgUserId: text(\"org_user_id\").notNull(),\n reason: text(\"reason\").notNull().default(\"\"),\n resolvedAt: timestamp(\"resolved_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 report per person, per comment.\n reporterUq: unique().on(t.orgId, t.commentId, t.orgUserId),\n commentFk: foreignKey({\n columns: [t.orgId, t.commentId],\n foreignColumns: [comments.orgId, comments.id],\n }).onDelete(\"cascade\"),\n reporterFk: foreignKey({\n columns: [t.orgId, t.orgUserId],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }),\n openIdx: index(\"comment_reports_open_idx\").on(t.orgId, t.commentId, t.resolvedAt),\n }),\n);\n\ntype _CommentsDrift = Expect<NoDrift<typeof comments.$inferSelect, Comment>>;\ntype _CommentReactionsDrift = Expect<\n NoDrift<typeof commentReactions.$inferSelect, CommentReaction>\n>;\ntype _CommentReportsDrift = Expect<NoDrift<typeof commentReports.$inferSelect, CommentReport>>;\n"],"mappings":"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"}
|
|
@@ -54,6 +54,23 @@ declare const entitlements: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
54
54
|
identity: undefined;
|
|
55
55
|
generated: undefined;
|
|
56
56
|
}, {}, {}>;
|
|
57
|
+
bundleId: import("drizzle-orm/pg-core").PgColumn<{
|
|
58
|
+
name: "bundle_id";
|
|
59
|
+
tableName: "entitlements";
|
|
60
|
+
dataType: "string";
|
|
61
|
+
columnType: "PgText";
|
|
62
|
+
data: string;
|
|
63
|
+
driverParam: string;
|
|
64
|
+
notNull: false;
|
|
65
|
+
hasDefault: false;
|
|
66
|
+
isPrimaryKey: false;
|
|
67
|
+
isAutoincrement: false;
|
|
68
|
+
hasRuntimeDefault: false;
|
|
69
|
+
enumValues: [string, ...string[]];
|
|
70
|
+
baseColumn: never;
|
|
71
|
+
identity: undefined;
|
|
72
|
+
generated: undefined;
|
|
73
|
+
}, {}, {}>;
|
|
57
74
|
contentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
58
75
|
name: "content_id";
|
|
59
76
|
tableName: "entitlements";
|
|
@@ -61,7 +78,7 @@ declare const entitlements: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
61
78
|
columnType: "PgText";
|
|
62
79
|
data: string;
|
|
63
80
|
driverParam: string;
|
|
64
|
-
notNull:
|
|
81
|
+
notNull: false;
|
|
65
82
|
hasDefault: false;
|
|
66
83
|
isPrimaryKey: false;
|
|
67
84
|
isAutoincrement: false;
|
|
@@ -139,6 +156,40 @@ declare const entitlements: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
139
156
|
identity: undefined;
|
|
140
157
|
generated: undefined;
|
|
141
158
|
}, {}, {}>;
|
|
159
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
160
|
+
name: "created_at";
|
|
161
|
+
tableName: "entitlements";
|
|
162
|
+
dataType: "date";
|
|
163
|
+
columnType: "PgTimestamp";
|
|
164
|
+
data: Date;
|
|
165
|
+
driverParam: string;
|
|
166
|
+
notNull: true;
|
|
167
|
+
hasDefault: true;
|
|
168
|
+
isPrimaryKey: false;
|
|
169
|
+
isAutoincrement: false;
|
|
170
|
+
hasRuntimeDefault: false;
|
|
171
|
+
enumValues: undefined;
|
|
172
|
+
baseColumn: never;
|
|
173
|
+
identity: undefined;
|
|
174
|
+
generated: undefined;
|
|
175
|
+
}, {}, {}>;
|
|
176
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
177
|
+
name: "updated_at";
|
|
178
|
+
tableName: "entitlements";
|
|
179
|
+
dataType: "date";
|
|
180
|
+
columnType: "PgTimestamp";
|
|
181
|
+
data: Date;
|
|
182
|
+
driverParam: string;
|
|
183
|
+
notNull: true;
|
|
184
|
+
hasDefault: true;
|
|
185
|
+
isPrimaryKey: false;
|
|
186
|
+
isAutoincrement: false;
|
|
187
|
+
hasRuntimeDefault: false;
|
|
188
|
+
enumValues: undefined;
|
|
189
|
+
baseColumn: never;
|
|
190
|
+
identity: undefined;
|
|
191
|
+
generated: undefined;
|
|
192
|
+
}, {}, {}>;
|
|
142
193
|
};
|
|
143
194
|
dialect: "pg";
|
|
144
195
|
}>;
|
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
import { orgUsers, organizations } from "./organizations.js";
|
|
2
|
-
import { contentItems } from "./content.js";
|
|
3
|
-
import {
|
|
2
|
+
import { bundles, contentItems } from "./content.js";
|
|
3
|
+
import { sql } from "drizzle-orm";
|
|
4
|
+
import { check, foreignKey, pgTable, primaryKey, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
4
5
|
import { genId } from "@headless-lms/core/shared/id";
|
|
5
6
|
//#region src/schema/entitlements.ts
|
|
6
7
|
const entitlements = pgTable("entitlements", {
|
|
7
8
|
orgId: text("org_id").notNull().references(() => organizations.id),
|
|
8
9
|
id: text("id").notNull().$defaultFn(() => genId("entitlement")),
|
|
9
10
|
orgUserId: text("org_user_id").notNull(),
|
|
10
|
-
|
|
11
|
+
bundleId: text("bundle_id"),
|
|
12
|
+
contentId: text("content_id"),
|
|
11
13
|
status: text("status", { enum: ["active", "revoked"] }).notNull().default("active"),
|
|
12
14
|
source: text("source").notNull().default("manual"),
|
|
13
15
|
grantedAt: timestamp("granted_at", { withTimezone: true }).notNull().defaultNow(),
|
|
14
|
-
expiresAt: timestamp("expires_at", { withTimezone: true })
|
|
16
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
17
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
18
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date())
|
|
15
19
|
}, (t) => ({
|
|
16
20
|
pk: primaryKey({ columns: [t.orgId, t.id] }),
|
|
17
21
|
contentFk: foreignKey({
|
|
18
22
|
columns: [t.orgId, t.contentId],
|
|
19
23
|
foreignColumns: [contentItems.orgId, contentItems.id]
|
|
20
24
|
}).onDelete("cascade"),
|
|
25
|
+
bundleFk: foreignKey({
|
|
26
|
+
columns: [t.orgId, t.bundleId],
|
|
27
|
+
foreignColumns: [bundles.orgId, bundles.id]
|
|
28
|
+
}).onDelete("cascade"),
|
|
21
29
|
orgUserFk: foreignKey({
|
|
22
30
|
columns: [t.orgId, t.orgUserId],
|
|
23
31
|
foreignColumns: [orgUsers.orgId, orgUsers.id]
|
|
24
32
|
}).onDelete("cascade"),
|
|
25
|
-
orgUserContentUq: unique().on(t.orgId, t.orgUserId, t.contentId)
|
|
33
|
+
orgUserContentUq: unique().on(t.orgId, t.orgUserId, t.contentId),
|
|
34
|
+
orgUserBundleUq: unique().on(t.orgId, t.orgUserId, t.bundleId),
|
|
35
|
+
targetCk: check("entitlements_target_check", sql`num_nonnulls(${t.bundleId}, ${t.contentId}) = 1`)
|
|
26
36
|
}));
|
|
27
37
|
//#endregion
|
|
28
38
|
export { entitlements };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entitlements.js","names":[],"sources":["../../src/schema/entitlements.ts"],"sourcesContent":["\nimport {
|
|
1
|
+
{"version":3,"file":"entitlements.js","names":[],"sources":["../../src/schema/entitlements.ts"],"sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n pgTable,\n text,\n timestamp,\n primaryKey,\n foreignKey,\n unique,\n check,\n} from \"drizzle-orm/pg-core\";\nimport type { Entitlement } from \"@headless-lms/core/schemas\";\nimport { genId } from \"@headless-lms/core/shared/id\";\nimport { organizations, orgUsers } from \"./organizations.js\";\nimport { bundles, contentItems } from \"./content.js\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const entitlements = pgTable(\n \"entitlements\",\n {\n orgId: text(\"org_id\")\n .notNull()\n .references(() => organizations.id),\n id: text(\"id\")\n .notNull()\n .$defaultFn(() => genId(\"entitlement\")),\n orgUserId: text(\"org_user_id\").notNull(),\n bundleId: text(\"bundle_id\"),\n contentId: text(\"content_id\"),\n status: text(\"status\", { enum: [\"active\", \"revoked\"] })\n .notNull()\n .default(\"active\"),\n // Free text: 'manual', 'import', integration ids, …\n source: text(\"source\").notNull().default(\"manual\"),\n grantedAt: timestamp(\"granted_at\", { withTimezone: true }).notNull().defaultNow(),\n expiresAt: timestamp(\"expires_at\", { withTimezone: true }), // null = lifetime\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 // Grants die with their content: deleting the registry row cascades here.\n contentFk: foreignKey({\n columns: [t.orgId, t.contentId],\n foreignColumns: [contentItems.orgId, contentItems.id],\n }).onDelete(\"cascade\"),\n // Grants die with their bundle, same as with their content.\n bundleFk: foreignKey({\n columns: [t.orgId, t.bundleId],\n foreignColumns: [bundles.orgId, bundles.id],\n }).onDelete(\"cascade\"),\n // org_users is org-scoped (composite PK) — the FK must match both columns.\n // Grants die with their org user: deleting the org_users row cascades here.\n orgUserFk: foreignKey({\n columns: [t.orgId, t.orgUserId],\n foreignColumns: [orgUsers.orgId, orgUsers.id],\n }).onDelete(\"cascade\"),\n // One grant per (org, org user, content) and per (org, org user, bundle) —\n // the unused column is null, and nulls never collide, so each constraint\n // only sees grants of its own kind. Both are the upsert targets.\n orgUserContentUq: unique().on(t.orgId, t.orgUserId, t.contentId),\n orgUserBundleUq: unique().on(t.orgId, t.orgUserId, t.bundleId),\n // A grant targets exactly one of: a bundle or a content item.\n targetCk: check(\n \"entitlements_target_check\",\n sql`num_nonnulls(${t.bundleId}, ${t.contentId}) = 1`,\n ),\n }),\n);\n\ntype _EntitlementsDrift = Expect<NoDrift<typeof entitlements.$inferSelect, Entitlement>>;\n"],"mappings":";;;;;;AAgBA,MAAa,eAAe,QAC1B,gBACA;CACE,OAAO,KAAK,QAAQ,CAAC,CAClB,QAAQ,CAAC,CACT,iBAAiB,cAAc,EAAE;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,QAAQ,CAAC,CACT,iBAAiB,MAAM,aAAa,CAAC;CACxC,WAAW,KAAK,aAAa,CAAC,CAAC,QAAQ;CACvC,UAAU,KAAK,WAAW;CAC1B,WAAW,KAAK,YAAY;CAC5B,QAAQ,KAAK,UAAU,EAAE,MAAM,CAAC,UAAU,SAAS,EAAE,CAAC,CAAC,CACpD,QAAQ,CAAC,CACT,QAAQ,QAAQ;CAEnB,QAAQ,KAAK,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,QAAQ;CACjD,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW;CAChF,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,WAAW,WAAW;EACpB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS;EAC9B,gBAAgB,CAAC,aAAa,OAAO,aAAa,EAAE;CACtD,CAAC,CAAC,CAAC,SAAS,SAAS;CAErB,UAAU,WAAW;EACnB,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ;EAC7B,gBAAgB,CAAC,QAAQ,OAAO,QAAQ,EAAE;CAC5C,CAAC,CAAC,CAAC,SAAS,SAAS;CAGrB,WAAW,WAAW;EACpB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS;EAC9B,gBAAgB,CAAC,SAAS,OAAO,SAAS,EAAE;CAC9C,CAAC,CAAC,CAAC,SAAS,SAAS;CAIrB,kBAAkB,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS;CAC/D,iBAAiB,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ;CAE7D,UAAU,MACR,6BACA,GAAG,gBAAgB,EAAE,SAAS,IAAI,EAAE,UAAU,MAChD;AACF,EACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","names":[],"sources":["../../src/schema/identity.ts"],"sourcesContent":["// identity tables — the person.\n//\n// One row per human, global, storing auth ID in `external_id`.\nimport { pgTable, text, timestamp } from
|
|
1
|
+
{"version":3,"file":"identity.js","names":[],"sources":["../../src/schema/identity.ts"],"sourcesContent":["// identity tables — the person.\n//\n// One row per human, global, storing auth ID in `external_id`.\nimport { pgTable, text, timestamp } from \"drizzle-orm/pg-core\";\nimport type { User } from \"@headless-lms/core/schemas\";\nimport { genId } from \"@headless-lms/core/shared/id\";\nimport type { Expect, NoDrift } from \"./drift.js\";\n\nexport const users = pgTable(\"users\", {\n id: text(\"id\")\n .primaryKey()\n .$defaultFn(() => genId(\"user\")),\n // auth engine's ID - e.g. better-auth.\n externalId: text(\"external_id\").unique(),\n email: text(\"email\").notNull().unique(),\n firstName: text(\"first_name\"),\n lastName: text(\"last_name\"),\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\ntype _UsersDrift = Expect<NoDrift<typeof users.$inferSelect, User>>;\n"],"mappings":";;;AAQA,MAAa,QAAQ,QAAQ,SAAS;CACpC,IAAI,KAAK,IAAI,CAAC,CACX,WAAW,CAAC,CACZ,iBAAiB,MAAM,MAAM,CAAC;CAEjC,YAAY,KAAK,aAAa,CAAC,CAAC,OAAO;CACvC,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO;CACtC,WAAW,KAAK,YAAY;CAC5B,UAAU,KAAK,WAAW;CAC1B,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"}
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { invites, orgUsers, organizations } from "./organizations.js";
|
|
2
|
-
import { activities, activityAssets, contentItems, courses, downloadAssets, downloads, modules } from "./content.js";
|
|
2
|
+
import { activities, activityAssets, bundleItems, bundles, contentItems, courses, downloadAssets, downloads, modules } from "./content.js";
|
|
3
3
|
import { entitlements } from "./entitlements.js";
|
|
4
4
|
import { progressRecords } from "./progress.js";
|
|
5
5
|
import { users } from "./identity.js";
|
|
@@ -11,8 +11,8 @@ import { automationRuns, automations } from "./automations.js";
|
|
|
11
11
|
import { settings } from "./settings.js";
|
|
12
12
|
import { commentReactions, commentReports, comments } 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, bundleItems, bundles, commentReactions, commentReports, comments, connections, contentItems, courses, credentials, downloadAssets, downloads, entitlements, eventOutbox, invites, modules, orgUsers, organizations, progressRecords, settings, 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, bundleItems, bundles, commentReactions, commentReports, comments, connections, contentItems, courses, credentials, downloadAssets, downloads, entitlements, eventOutbox, index_d_exports, invites, modules, orgUsers, organizations, progressRecords, settings, users };
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/schema/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
|
2
2
|
import { users } from "./identity.js";
|
|
3
3
|
import { invites, orgUsers, organizations } from "./organizations.js";
|
|
4
4
|
import { assets } from "./assets.js";
|
|
5
|
-
import { activities, activityAssets, contentItems, courses, downloadAssets, downloads, modules } from "./content.js";
|
|
5
|
+
import { activities, activityAssets, bundleItems, bundles, contentItems, courses, downloadAssets, downloads, modules } from "./content.js";
|
|
6
6
|
import { entitlements } from "./entitlements.js";
|
|
7
7
|
import { progressRecords } from "./progress.js";
|
|
8
8
|
import { credentials } from "./credentials.js";
|
|
@@ -18,6 +18,8 @@ var schema_exports = /* @__PURE__ */ __exportAll({
|
|
|
18
18
|
assets: () => assets,
|
|
19
19
|
automationRuns: () => automationRuns,
|
|
20
20
|
automations: () => automations,
|
|
21
|
+
bundleItems: () => bundleItems,
|
|
22
|
+
bundles: () => bundles,
|
|
21
23
|
commentReactions: () => commentReactions,
|
|
22
24
|
commentReports: () => commentReports,
|
|
23
25
|
comments: () => comments,
|
|
@@ -38,6 +40,6 @@ var schema_exports = /* @__PURE__ */ __exportAll({
|
|
|
38
40
|
users: () => users
|
|
39
41
|
});
|
|
40
42
|
//#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 };
|
|
43
|
+
export { activities, activityAssets, assets, automationRuns, automations, bundleItems, bundles, commentReactions, commentReports, comments, connections, contentItems, courses, credentials, downloadAssets, downloads, entitlements, eventOutbox, invites, modules, orgUsers, organizations, progressRecords, schema_exports, settings, users };
|
|
42
44
|
|
|
43
45
|
//# sourceMappingURL=index.js.map
|
package/dist/schema/index.js.map
CHANGED
|
@@ -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
|
|
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
|
|
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"}
|
|
@@ -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
|
}>;
|
|
@@ -47,7 +47,8 @@ const invites = pgTable("invites", {
|
|
|
47
47
|
invitedBy: text("invited_by").notNull().references(() => users.id),
|
|
48
48
|
tokenHash: text("token_hash").unique(),
|
|
49
49
|
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
50
|
-
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
50
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
51
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => /* @__PURE__ */ new Date())
|
|
51
52
|
}, (t) => ({
|
|
52
53
|
pk: primaryKey({ columns: [t.orgId, t.id] }),
|
|
53
54
|
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
|
|
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\", { 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 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":"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"}
|
package/dist/schema/outbox.d.ts
CHANGED
|
@@ -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";
|
package/dist/schema/outbox.js
CHANGED
|
@@ -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
|
|
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";
|
package/dist/schema/progress.js
CHANGED
|
@@ -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
|
|
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
|
|
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"}
|
package/dist/unit-of-work.js
CHANGED
|
@@ -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
|
-
|
|
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
|
package/dist/unit-of-work.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unit-of-work.js","names":[],"sources":["../src/unit-of-work.ts"],"sourcesContent":["import type { NodePgDatabase } from
|
|
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");
|