@happyvertical/smrt-social 0.54.3 → 0.55.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.
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-social",
5
- "packageVersion": "0.54.3",
5
+ "packageVersion": "0.55.0",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-social:OAuthState": {
8
8
  "name": "oauthstate",
@@ -65,6 +65,15 @@
65
65
  "expiresAt": {
66
66
  "type": "datetime",
67
67
  "required": false
68
+ },
69
+ "createdByUserId": {
70
+ "type": "crossPackageRef",
71
+ "required": false,
72
+ "related": "@happyvertical/smrt-users:User"
73
+ },
74
+ "returnTo": {
75
+ "type": "text",
76
+ "required": false
68
77
  }
69
78
  },
70
79
  "methods": {
@@ -142,7 +151,7 @@
142
151
  "collectionExportName": "OAuthStateCollection",
143
152
  "schema": {
144
153
  "tableName": "oauth_states",
145
- "ddl": "CREATE TABLE IF NOT EXISTS \"oauth_states\" (\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"_meta_type\" TEXT NOT NULL,\n \"_meta_data\" JSON,\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"tenant_id\" UUID,\n \"platform\" TEXT DEFAULT 'youtube',\n \"state\" TEXT DEFAULT '',\n \"code_verifier\" TEXT,\n \"redirect_uri\" TEXT DEFAULT '',\n \"scopes\" JSON DEFAULT '[]',\n \"expires_at\" TIMESTAMP\n);",
154
+ "ddl": "CREATE TABLE IF NOT EXISTS \"oauth_states\" (\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"_meta_type\" TEXT NOT NULL,\n \"_meta_data\" JSON,\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"tenant_id\" UUID,\n \"platform\" TEXT DEFAULT 'youtube',\n \"state\" TEXT DEFAULT '',\n \"code_verifier\" TEXT,\n \"redirect_uri\" TEXT DEFAULT '',\n \"scopes\" JSON DEFAULT '[]',\n \"expires_at\" TIMESTAMP,\n \"created_by_user_id\" UUID,\n \"return_to\" TEXT\n);",
146
155
  "columns": {
147
156
  "id": {
148
157
  "type": "UUID",
@@ -209,6 +218,15 @@
209
218
  "expires_at": {
210
219
  "type": "TIMESTAMP",
211
220
  "notNull": false
221
+ },
222
+ "created_by_user_id": {
223
+ "type": "UUID",
224
+ "referenceKind": "crossPackageRef",
225
+ "notNull": false
226
+ },
227
+ "return_to": {
228
+ "type": "TEXT",
229
+ "notNull": false
212
230
  }
213
231
  },
214
232
  "indexes": [
@@ -235,9 +253,15 @@
235
253
  "tenant_id",
236
254
  "created_at"
237
255
  ]
256
+ },
257
+ {
258
+ "name": "oauth_states_created_by_user_id_idx",
259
+ "columns": [
260
+ "created_by_user_id"
261
+ ]
238
262
  }
239
263
  ],
240
- "version": "709e111f"
264
+ "version": "ca0ff7c5"
241
265
  },
242
266
  "importPath": "@happyvertical/smrt-social"
243
267
  },
@@ -1161,6 +1185,20 @@
1161
1185
  "isStatic": false,
1162
1186
  "isPublic": true
1163
1187
  },
1188
+ "consume": {
1189
+ "name": "consume",
1190
+ "async": true,
1191
+ "parameters": [
1192
+ {
1193
+ "name": "state",
1194
+ "type": "OAuthState",
1195
+ "optional": false
1196
+ }
1197
+ ],
1198
+ "returnType": "Promise<boolean>",
1199
+ "isStatic": false,
1200
+ "isPublic": true
1201
+ },
1164
1202
  "findExpired": {
1165
1203
  "name": "findExpired",
1166
1204
  "async": true,
@@ -1199,7 +1237,7 @@
1199
1237
  "collectionExportName": "OAuthStateCollectionCollection",
1200
1238
  "schema": {
1201
1239
  "tableName": "oauth_states",
1202
- "ddl": "CREATE TABLE IF NOT EXISTS \"oauth_states\" (\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"_meta_type\" TEXT NOT NULL,\n \"_meta_data\" JSON,\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"tenant_id\" UUID,\n \"platform\" TEXT DEFAULT 'youtube',\n \"state\" TEXT DEFAULT '',\n \"code_verifier\" TEXT,\n \"redirect_uri\" TEXT DEFAULT '',\n \"scopes\" JSON DEFAULT '[]',\n \"expires_at\" TIMESTAMP\n);",
1240
+ "ddl": "CREATE TABLE IF NOT EXISTS \"oauth_states\" (\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"_meta_type\" TEXT NOT NULL,\n \"_meta_data\" JSON,\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"tenant_id\" UUID,\n \"platform\" TEXT DEFAULT 'youtube',\n \"state\" TEXT DEFAULT '',\n \"code_verifier\" TEXT,\n \"redirect_uri\" TEXT DEFAULT '',\n \"scopes\" JSON DEFAULT '[]',\n \"expires_at\" TIMESTAMP,\n \"created_by_user_id\" UUID,\n \"return_to\" TEXT\n);",
1203
1241
  "columns": {
1204
1242
  "id": {
1205
1243
  "type": "UUID",
@@ -1266,6 +1304,15 @@
1266
1304
  "expires_at": {
1267
1305
  "type": "TIMESTAMP",
1268
1306
  "notNull": false
1307
+ },
1308
+ "created_by_user_id": {
1309
+ "type": "UUID",
1310
+ "referenceKind": "crossPackageRef",
1311
+ "notNull": false
1312
+ },
1313
+ "return_to": {
1314
+ "type": "TEXT",
1315
+ "notNull": false
1269
1316
  }
1270
1317
  },
1271
1318
  "indexes": [
@@ -1292,9 +1339,15 @@
1292
1339
  "tenant_id",
1293
1340
  "created_at"
1294
1341
  ]
1342
+ },
1343
+ {
1344
+ "name": "oauth_states_created_by_user_id_idx",
1345
+ "columns": [
1346
+ "created_by_user_id"
1347
+ ]
1295
1348
  }
1296
1349
  ],
1297
- "version": "709e111f"
1350
+ "version": "ca0ff7c5"
1298
1351
  },
1299
1352
  "importPath": "@happyvertical/smrt-social"
1300
1353
  },
@@ -39,6 +39,14 @@ export interface OAuthStateOptions extends SmrtObjectOptions {
39
39
  * Tenant ID for multi-tenant isolation
40
40
  */
41
41
  tenantId?: string | null;
42
+ /**
43
+ * User who started the OAuth flow
44
+ */
45
+ createdByUserId?: string | null;
46
+ /**
47
+ * Application-defined path to return to after the callback
48
+ */
49
+ returnTo?: string | null;
42
50
  }
43
51
  /**
44
52
  * Temporary OAuth state for social account connection
@@ -47,6 +55,9 @@ export interface OAuthStateOptions extends SmrtObjectOptions {
47
55
  * - Verify callback requests match initiated requests (CSRF protection)
48
56
  * - Store PKCE code verifier for code exchange
49
57
  * - Track redirect URI and scopes for verification
58
+ * - Bind the flow to the user who started it (`createdByUserId`) and record
59
+ * where the host returns afterwards (`returnTo`), so one fixed callback
60
+ * can serve every tenant
50
61
  *
51
62
  * These records should be cleaned up after successful connection
52
63
  * or after expiration.
@@ -103,6 +114,22 @@ export declare class OAuthState extends SmrtObject {
103
114
  * States should be short-lived (10 minutes typical)
104
115
  */
105
116
  expiresAt: Date;
117
+ /**
118
+ * User who started the OAuth flow.
119
+ *
120
+ * A host with one fixed callback for every tenant compares this to the
121
+ * signed-in user on callback and rejects a mismatch, so a forwarded or
122
+ * leaked state cannot be completed by someone else. A `@crossPackageRef` to
123
+ * `@happyvertical/smrt-users:User` (native uuid on PostgreSQL, no DDL FK).
124
+ * Null for states created before the column existed.
125
+ */
126
+ createdByUserId: string | null;
127
+ /**
128
+ * Application-defined path to return to after the callback, for example the
129
+ * settings page that started the flow. Opaque to the framework: the host
130
+ * that reads it must validate it as a same-origin path before redirecting.
131
+ */
132
+ returnTo: string | null;
106
133
  constructor(options?: OAuthStateOptions);
107
134
  /**
108
135
  * Check if the state has expired
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-state.d.ts","sourceRoot":"","sources":["../src/oauth-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAE5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAE9B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBASa,UAAW,SAAQ,UAAU;IACxC;;OAEG;IAEH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B;;OAEG;IACH,QAAQ,EAAE,kBAAkB,CAAa;IAEzC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAM;IAEnB;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEnC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAM;IAEzB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAM;IAEtB;;;OAGG;IACH,SAAS,EAAE,IAAI,CAAyC;gBAE5C,OAAO,GAAE,iBAAsB;IAc3C;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;IAI3C;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,MAAM;IAI9B;;;OAGG;IACH,MAAM,CAAC,oBAAoB,IAAI,MAAM;IAQrC;;;OAGG;WACU,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAOtE"}
1
+ {"version":3,"file":"oauth-state.d.ts","sourceRoot":"","sources":["../src/oauth-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAmB,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAE7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D;;OAEG;IACH,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAE9B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBASa,UAAW,SAAQ,UAAU;IACxC;;OAEG;IAEH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B;;OAEG;IACH,QAAQ,EAAE,kBAAkB,CAAa;IAEzC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAM;IAEnB;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEnC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAM;IAEzB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAM;IAEtB;;;OAGG;IACH,SAAS,EAAE,IAAI,CAAyC;IAExD;;;;;;;;OAQG;IAEH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEtC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAEnB,OAAO,GAAE,iBAAsB;IAiB3C;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;IAI3C;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,MAAM;IAI9B;;;OAGG;IACH,MAAM,CAAC,oBAAoB,IAAI,MAAM;IAQrC;;;OAGG;WACU,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAOtE"}
@@ -3,13 +3,13 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-social",
6
- "packageVersion": "0.54.3",
6
+ "packageVersion": "0.55.0",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "967ba1c6d3cec644e654b6cdad9ffb6f29e8348295dbf5e1ce80d76204214e84",
11
- "packageJson": "5c1e680ecc87bcaea3111943bba6c158c69e089e098f21d2fd97dfd6a9424ef7",
12
- "agents": "8649047a57ee16eb46557ab5a9504315421f6f78b434ee19ed0d4df24b45f20d"
10
+ "manifest": "177bb09655fcc57095a727799f2aae13a0c771c6dfbd399e81c0b71c658f8631",
11
+ "packageJson": "495d55f590a9bc985e6c6703e1b0c1f249397da8bace6d8b820f7a7612ee522c",
12
+ "agents": "7596f706e6513fd86254f510301ec9696520655bdf19f932ec2267ca9d5767ee"
13
13
  },
14
14
  "exports": [
15
15
  ".",
@@ -64,7 +64,7 @@
64
64
  "youtube"
65
65
  ],
66
66
  "risks": [
67
- "cross-package-refs:3",
67
+ "cross-package-refs:4",
68
68
  "sensitive-fields-excluded",
69
69
  "sti-inheritance"
70
70
  ],
@@ -134,9 +134,30 @@
134
134
  "type": "datetime",
135
135
  "required": false,
136
136
  "columnType": "TIMESTAMP"
137
+ },
138
+ {
139
+ "name": "createdByUserId",
140
+ "type": "crossPackageRef",
141
+ "required": false,
142
+ "related": "@happyvertical/smrt-users:User",
143
+ "columnType": "UUID"
144
+ },
145
+ {
146
+ "name": "returnTo",
147
+ "type": "text",
148
+ "required": false,
149
+ "columnType": "TEXT"
150
+ }
151
+ ],
152
+ "relationships": [
153
+ {
154
+ "name": "createdByUserId",
155
+ "type": "crossPackageRef",
156
+ "required": false,
157
+ "related": "@happyvertical/smrt-users:User",
158
+ "columnType": "UUID"
137
159
  }
138
160
  ],
139
- "relationships": [],
140
161
  "methods": [
141
162
  "generateCodeChallenge",
142
163
  "generateCodeVerifier",
@@ -302,6 +323,7 @@
302
323
  }
303
324
  ],
304
325
  "relationshipFeatures": [
326
+ "crossPackageRef",
305
327
  "uuidColumns"
306
328
  ],
307
329
  "tags": [],
@@ -1079,11 +1101,20 @@
1079
1101
  "fields": [],
1080
1102
  "relationships": [],
1081
1103
  "methods": [
1104
+ "consume",
1082
1105
  "deleteExpired",
1083
1106
  "findByState",
1084
1107
  "findExpired"
1085
1108
  ],
1086
1109
  "methodSignatures": [
1110
+ {
1111
+ "name": "consume",
1112
+ "async": true,
1113
+ "params": [
1114
+ "state: OAuthState"
1115
+ ],
1116
+ "returns": "Promise<boolean>"
1117
+ },
1087
1118
  {
1088
1119
  "name": "deleteExpired",
1089
1120
  "async": true,
@@ -1140,6 +1171,12 @@
1140
1171
  "operation": "findByState",
1141
1172
  "objectName": "@happyvertical/smrt-social:OAuthStateCollection"
1142
1173
  },
1174
+ {
1175
+ "kind": "cli",
1176
+ "name": "oauthstatecollection_consume",
1177
+ "operation": "consume",
1178
+ "objectName": "@happyvertical/smrt-social:OAuthStateCollection"
1179
+ },
1143
1180
  {
1144
1181
  "kind": "cli",
1145
1182
  "name": "oauthstatecollection_findExpired",
@@ -1153,6 +1190,15 @@
1153
1190
  "objectName": "@happyvertical/smrt-social:OAuthStateCollection"
1154
1191
  }
1155
1192
  ],
1193
+ "withheldSurfaces": [
1194
+ {
1195
+ "kind": "api",
1196
+ "operation": "consume",
1197
+ "code": "not-wireable",
1198
+ "reason": "not routed: parameter `state`: `OAuthState` is a model class instance, not JSON data",
1199
+ "objectName": "@happyvertical/smrt-social:OAuthStateCollection"
1200
+ }
1201
+ ],
1156
1202
  "relationshipFeatures": [
1157
1203
  "uuidColumns"
1158
1204
  ],
@@ -1968,6 +2014,12 @@
1968
2014
  "operation": "findByState",
1969
2015
  "objectName": "@happyvertical/smrt-social:OAuthStateCollection"
1970
2016
  },
2017
+ {
2018
+ "kind": "cli",
2019
+ "name": "oauthstatecollection_consume",
2020
+ "operation": "consume",
2021
+ "objectName": "@happyvertical/smrt-social:OAuthStateCollection"
2022
+ },
1971
2023
  {
1972
2024
  "kind": "cli",
1973
2025
  "name": "oauthstatecollection_findExpired",
@@ -2212,11 +2264,11 @@
2212
2264
  "prompts": [],
2213
2265
  "relationshipsV2": {
2214
2266
  "foreignKeyFields": 2,
2215
- "crossPackageRefFields": 3,
2267
+ "crossPackageRefFields": 4,
2216
2268
  "junctionCollections": 0,
2217
2269
  "hierarchicalObjects": 0,
2218
2270
  "polymorphicAssociations": 0,
2219
- "uuidColumns": 26
2271
+ "uuidColumns": 28
2220
2272
  },
2221
- "agentDoc": "# @happyvertical/smrt-social\n\nSocial media account management with OAuth and post scheduling. Supports YouTube, Threads, X (Twitter), Bluesky.\n\n## Models\n\n- **SocialAccount** (STI): `platform`, `accessToken`/`refreshToken`, `tokenExpiresAt`, `status` (connected/expired/error), `linkBehavior` (description/reply/none). `isTokenExpired` checks with 5-min buffer. `isReady` gate checks active + connected + token present + not expired.\n- **SocialPost**: `scheduledAt`, `publishedAt`, `status` (draft/scheduled/publishing/published/failed), `analytics` JSON (views/likes/comments/shares/clicks). `createdByUserId` (nullable `@crossPackageRef` to `smrt-users:User`, uuid on PostgreSQL) records the poster; pass it to `createDraft()` so a failed publish can be reported to that person. Agent/schedule posts leave it null; `recordPublishSuccess`/`Failure` never change it. Adding the column is additive: consumers run `db:migrate`.\n- **OAuthState** (STI): CSRF token + PKCE `codeVerifier` with 10-min TTL.\n\n## Gotchas\n\n- **Tokens not encrypted**: OAuth tokens stored as plaintext — TODO for smrt-secrets integration\n- **No auto-publishing**: `scheduledAt` is metadata only — app must implement job runner to trigger publishing\n- **Analytics manual**: `analytics` field must be updated by platform sync, not auto-populated\n- **Platform enum hardcoded**: youtube/threads/x/bluesky — extending requires code changes\n- **OAuthState TTL**: 10 minutes, app must clean up expired states\n- **Optional tenancy** on all models\n- **Relationship targets**: `SocialPost.socialAccountId` and\n `SocialPostAnalyticsSnapshot.socialPostId` are same-package `@foreignKey`\n columns; `SocialPost.videoContentId` is a `@crossPackageRef` to\n `@happyvertical/smrt-video:VideoContent` (no value import back into this\n package). They previously used `@foreignKey(() => X)`, whose target resolved\n to `''`, so none of them carried a relationship edge (#2379).\n"
2273
+ "agentDoc": "# @happyvertical/smrt-social\n\nSocial media account management with OAuth and post scheduling. Supports YouTube, Threads, X (Twitter), Bluesky.\n\n## Models\n\n- **SocialAccount** (STI): `platform`, `accessToken`/`refreshToken`, `tokenExpiresAt`, `status` (connected/expired/error), `linkBehavior` (description/reply/none). `isTokenExpired` checks with 5-min buffer. `isReady` gate checks active + connected + token present + not expired.\n- **SocialPost**: `scheduledAt`, `publishedAt`, `status` (draft/scheduled/publishing/published/failed), `analytics` JSON (views/likes/comments/shares/clicks). `createdByUserId` (nullable `@crossPackageRef` to `smrt-users:User`, uuid on PostgreSQL) records the poster; pass it to `createDraft()` so a failed publish can be reported to that person. Agent/schedule posts leave it null; `recordPublishSuccess`/`Failure` never change it. Adding the column is additive: consumers run `db:migrate`.\n- **OAuthState** (STI): CSRF token + PKCE `codeVerifier` with 10-min TTL. `createdByUserId` (nullable `@crossPackageRef` to `smrt-users:User`) binds the flow to its initiator and `returnTo` stores an opaque host path; a host with one fixed callback for every tenant must reject a different user and validate `returnTo` as same-origin. `OAuthStateCollection.consume(state)` is the single-use arbiter (revision-guarded delete; `false` when another caller already consumed it). Both columns are additive: consumers run `db:migrate`.\n\n## Gotchas\n\n- **Tokens not encrypted**: OAuth tokens stored as plaintext — TODO for smrt-secrets integration\n- **No auto-publishing**: `scheduledAt` is metadata only — app must implement job runner to trigger publishing\n- **Analytics manual**: `analytics` field must be updated by platform sync, not auto-populated\n- **Platform enum hardcoded**: youtube/threads/x/bluesky — extending requires code changes\n- **OAuthState TTL**: 10 minutes, app must clean up expired states\n- **Optional tenancy** on all models\n- **Relationship targets**: `SocialPost.socialAccountId` and\n `SocialPostAnalyticsSnapshot.socialPostId` are same-package `@foreignKey`\n columns; `SocialPost.videoContentId` is a `@crossPackageRef` to\n `@happyvertical/smrt-video:VideoContent` (no value import back into this\n package). They previously used `@foreignKey(() => X)`, whose target resolved\n to `''`, so none of them carried a relationship edge (#2379).\n"
2222
2274
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-social",
3
- "version": "0.54.3",
3
+ "version": "0.55.0",
4
4
  "type": "module",
5
5
  "smrtRawPrimitives": "strict",
6
6
  "description": "Social media account management for multi-platform publishing in the SMRT ecosystem",
@@ -39,18 +39,18 @@
39
39
  "AGENTS.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@happyvertical/smrt-config": "0.54.3",
43
- "@happyvertical/smrt-content": "0.54.3",
44
- "@happyvertical/smrt-core": "0.54.3",
45
- "@happyvertical/smrt-secrets": "0.54.3",
46
- "@happyvertical/smrt-tenancy": "0.54.3",
47
- "@happyvertical/smrt-ui": "0.54.3",
48
- "@happyvertical/smrt-video": "0.54.3",
42
+ "@happyvertical/smrt-config": "0.55.0",
43
+ "@happyvertical/smrt-content": "0.55.0",
44
+ "@happyvertical/smrt-core": "0.55.0",
45
+ "@happyvertical/smrt-secrets": "0.55.0",
46
+ "@happyvertical/smrt-tenancy": "0.55.0",
47
+ "@happyvertical/smrt-ui": "0.55.0",
48
+ "@happyvertical/smrt-video": "0.55.0",
49
49
  "@happyvertical/utils": "^0.102.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@happyvertical/logger": "^0.102.1",
53
- "@happyvertical/smrt-vitest": "0.54.3",
53
+ "@happyvertical/smrt-vitest": "0.55.0",
54
54
  "@happyvertical/sql": "^0.102.1",
55
55
  "@sveltejs/package": "^2.5.8",
56
56
  "@types/node": "24.13.6",