@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.
package/AGENTS.md CHANGED
@@ -6,7 +6,7 @@ Social media account management with OAuth and post scheduling. Supports YouTube
6
6
 
7
7
  - **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.
8
8
  - **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`.
9
- - **OAuthState** (STI): CSRF token + PKCE `codeVerifier` with 10-min TTL.
9
+ - **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`.
10
10
 
11
11
  ## Gotchas
12
12
 
package/README.md CHANGED
@@ -47,9 +47,12 @@ const state = new OAuthState({
47
47
  codeVerifier: OAuthState.generateCodeVerifier(),
48
48
  redirectUri: 'https://app.example.com/oauth/callback',
49
49
  scopes: ['youtube.upload', 'youtube.readonly'],
50
+ createdByUserId: currentUser.id, // reject a different user on callback
51
+ returnTo: '/settings/social', // host-validated same-origin path
50
52
  });
51
53
  await state.save();
52
- // On callback: state.verifyState(callbackState), then exchange code for tokens
54
+ // On callback: state.verifyState(callbackState), check the user, then
55
+ // `await states.consume(state)` (false = already used) before exchanging the code
53
56
  ```
54
57
 
55
58
  ## API
@@ -60,7 +63,7 @@ await state.save();
60
63
  |--------|------------|
61
64
  | `SocialAccount` | Connected platform account with OAuth credentials and publishing settings |
62
65
  | `SocialPost` | Scheduled or published post with analytics tracking; `createdByUserId` records the poster |
63
- | `OAuthState` | Temporary OAuth flow state with CSRF protection and PKCE support |
66
+ | `OAuthState` | Temporary OAuth flow state with CSRF protection and PKCE support; `createdByUserId` and `returnTo` bind it to its initiator and return page |
64
67
 
65
68
  ### Types
66
69
 
@@ -84,6 +87,7 @@ await state.save();
84
87
  - `OAuthState.isValid` -- not expired and state token present
85
88
  - `OAuthState.verifyState(callback)` -- CSRF verification for OAuth callbacks
86
89
  - `OAuthState.generateCodeChallenge(verifier)` -- PKCE S256 challenge generation
90
+ - `OAuthStateCollection.consume(state)` -- single-use consumption; `false` when another caller consumed it first
87
91
 
88
92
  ## Dependencies
89
93
 
@@ -3,6 +3,16 @@ import { OAuthState } from '../oauth-state.js';
3
3
  export declare class OAuthStateCollection extends SmrtCollection<OAuthState> {
4
4
  static readonly _itemClass: typeof OAuthState;
5
5
  findByState(state: string): Promise<OAuthState | null>;
6
+ /**
7
+ * Consume a loaded state exactly once.
8
+ *
9
+ * Deletes the record with a revision-guarded delete, so when two callbacks
10
+ * race on the same state only one delete removes the row. Returns `true`
11
+ * for that caller and `false` for every caller whose row was already gone
12
+ * or changed; any other failure propagates. Call it before acting on the
13
+ * state (exchanging the code), and stop when it returns `false`.
14
+ */
15
+ consume(state: OAuthState): Promise<boolean>;
6
16
  findExpired(now?: Date): Promise<OAuthState[]>;
7
17
  deleteExpired(now?: Date): Promise<number>;
8
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-state-collection.d.ts","sourceRoot":"","sources":["../../src/collections/oauth-state-collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,qBAAa,oBAAqB,SAAQ,cAAc,CAAC,UAAU,CAAC;IAClE,MAAM,CAAC,QAAQ,CAAC,UAAU,oBAAc;IAElC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAItD,WAAW,CAAC,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAO1D,aAAa,CAAC,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;CAK7D"}
1
+ {"version":3,"file":"oauth-state-collection.d.ts","sourceRoot":"","sources":["../../src/collections/oauth-state-collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,qBAAa,oBAAqB,SAAQ,cAAc,CAAC,UAAU,CAAC;IAClE,MAAM,CAAC,QAAQ,CAAC,UAAU,oBAAc;IAElC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAI5D;;;;;;;;OAQG;IACG,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB5C,WAAW,CAAC,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAO1D,aAAa,CAAC,GAAG,GAAE,IAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;CAK7D"}
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { getSocialPlatformSetup } from "./server.js";
2
- import { ObjectRegistry, SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, smrt } from "@happyvertical/smrt-core";
2
+ import { ObjectRegistry, RuntimeError, SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, smrt } from "@happyvertical/smrt-core";
3
3
  import { TenantScoped, getCurrentTenant, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { SecretService } from "@happyvertical/smrt-secrets";
6
6
  //#region src/__smrt-register__.ts
7
- ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-social","packageVersion":"0.54.3","objects":{"@happyvertical/smrt-social:OAuthState":{"name":"oauthstate","className":"OAuthState","qualifiedName":"@happyvertical/smrt-social:OAuthState","collection":"oauthstates","filePath":"/home/runner/work/smrt/smrt/packages/social/src/oauth-state.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"platform":{"type":"text","required":false,"default":"youtube"},"state":{"type":"text","required":false,"default":""},"codeVerifier":{"type":"text","required":false},"redirectUri":{"type":"text","required":false,"default":""},"scopes":{"type":"json","required":false,"default":[]},"expiresAt":{"type":"datetime","required":false}},"methods":{"verifyState":{"name":"verifyState","async":false,"parameters":[{"name":"callbackState","type":"string","optional":false}],"returnType":"boolean","isStatic":false,"isPublic":true},"generateState":{"name":"generateState","async":false,"parameters":[],"returnType":"string","isStatic":true,"isPublic":true},"generateCodeVerifier":{"name":"generateCodeVerifier","async":false,"parameters":[],"returnType":"string","isStatic":true,"isPublic":true},"generateCodeChallenge":{"name":"generateCodeChallenge","async":true,"parameters":[{"name":"verifier","type":"string","optional":false}],"returnType":"Promise<string>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","delete"]},"mcp":false,"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"OAuthState","collectionExportName":"OAuthStateCollection","schema":{"tableName":"oauth_states","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);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"state":{"type":"TEXT","notNull":false,"default":""},"code_verifier":{"type":"TEXT","notNull":false},"redirect_uri":{"type":"TEXT","notNull":false,"default":""},"scopes":{"type":"JSON","notNull":false,"default":[]},"expires_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"oauth_states_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"oauth_states_meta_type_idx","columns":["_meta_type"]},{"name":"oauth_states_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"709e111f"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialAccount":{"name":"socialaccount","className":"SocialAccount","qualifiedName":"@happyvertical/smrt-social:SocialAccount","collection":"socialaccounts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/social-account.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"name":{"type":"text","required":false,"default":""},"platform":{"type":"text","required":false,"default":"youtube"},"platformUserId":{"type":"text","required":false},"platformUsername":{"type":"text","required":false},"platformUrl":{"type":"text","required":false},"accessToken":{"type":"text","required":false},"refreshToken":{"type":"text","required":false},"credentialSecretId":{"type":"text","required":false},"accessTokenSecretName":{"type":"text","required":false},"refreshTokenSecretName":{"type":"text","required":false},"tokenExpiresAt":{"type":"datetime","required":false},"isActive":{"type":"boolean","required":false,"default":true},"defaultHashtags":{"type":"json","required":false,"default":[]},"scopes":{"type":"json","required":false,"default":[]},"missingPermissions":{"type":"json","required":false,"default":[]},"linkBehavior":{"type":"text","required":false,"default":"description"},"publishMode":{"type":"text","required":false,"default":"dry_run"},"publicPublishingAllowed":{"type":"boolean","required":false,"default":false},"status":{"type":"text","required":false,"default":"connected"},"errorMessage":{"type":"text","required":false}},"methods":{"getSlug":{"name":"getSlug","async":true,"parameters":[],"returnType":"Promise<string | null | undefined>","isStatic":false,"isPublic":true},"setCredentials":{"name":"setCredentials","async":true,"parameters":[{"name":"credentials","type":"Record<string, unknown>","optional":false},{"name":"options","type":"object","optional":true,"memberTypes":["string"]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getCredentials":{"name":"getCredentials","async":true,"parameters":[],"returnType":"Promise<Record<string, unknown> | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"SocialAccount","collectionExportName":"SocialAccountCollection","schema":{"tableName":"social_accounts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_accounts\\" (\\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 \\"name\\" TEXT DEFAULT '',\\n \\"platform\\" TEXT DEFAULT 'youtube',\\n \\"platform_user_id\\" TEXT,\\n \\"platform_username\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"access_token\\" TEXT,\\n \\"refresh_token\\" TEXT,\\n \\"credential_secret_id\\" TEXT,\\n \\"access_token_secret_name\\" TEXT,\\n \\"refresh_token_secret_name\\" TEXT,\\n \\"token_expires_at\\" TIMESTAMP,\\n \\"is_active\\" BOOLEAN DEFAULT TRUE,\\n \\"default_hashtags\\" JSON DEFAULT '[]',\\n \\"scopes\\" JSON DEFAULT '[]',\\n \\"missing_permissions\\" JSON DEFAULT '[]',\\n \\"link_behavior\\" TEXT DEFAULT 'description',\\n \\"publish_mode\\" TEXT DEFAULT 'dry_run',\\n \\"public_publishing_allowed\\" BOOLEAN DEFAULT FALSE,\\n \\"status\\" TEXT DEFAULT 'connected',\\n \\"error_message\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"name":{"type":"TEXT","notNull":false,"default":""},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"platform_user_id":{"type":"TEXT","notNull":false},"platform_username":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"access_token":{"type":"TEXT","notNull":false},"refresh_token":{"type":"TEXT","notNull":false},"credential_secret_id":{"type":"TEXT","notNull":false},"access_token_secret_name":{"type":"TEXT","notNull":false},"refresh_token_secret_name":{"type":"TEXT","notNull":false},"token_expires_at":{"type":"TIMESTAMP","notNull":false},"is_active":{"type":"BOOLEAN","notNull":false,"default":true},"default_hashtags":{"type":"JSON","notNull":false,"default":[]},"scopes":{"type":"JSON","notNull":false,"default":[]},"missing_permissions":{"type":"JSON","notNull":false,"default":[]},"link_behavior":{"type":"TEXT","notNull":false,"default":"description"},"publish_mode":{"type":"TEXT","notNull":false,"default":"dry_run"},"public_publishing_allowed":{"type":"BOOLEAN","notNull":false,"default":false},"status":{"type":"TEXT","notNull":false,"default":"connected"},"error_message":{"type":"TEXT","notNull":false}},"indexes":[{"name":"social_accounts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_accounts_meta_type_idx","columns":["_meta_type"]},{"name":"social_accounts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"0c175da6"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPostAnalyticsSnapshot":{"name":"socialpostanalyticssnapshot","className":"SocialPostAnalyticsSnapshot","qualifiedName":"@happyvertical/smrt-social:SocialPostAnalyticsSnapshot","collection":"socialpostanalyticssnapshots","filePath":"/home/runner/work/smrt/smrt/packages/social/src/social-post-analytics-snapshot.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"socialPostId":{"type":"foreignKey","required":false,"related":"SocialPost"},"platform":{"type":"text","required":true,"_meta":{"required":true}},"analytics":{"type":"json","required":false},"raw":{"type":"json","required":false,"_meta":{"nullable":true}},"capturedAt":{"type":"datetime","required":false}},"methods":{},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","delete"]},"mcp":{"include":["list","get"]},"cli":true,"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"SocialPostAnalyticsSnapshot","collectionExportName":"SocialPostAnalyticsSnapshotCollection","validationRules":[{"field":"platform","rule":"required","fieldType":"text"}],"schema":{"tableName":"social_post_analytics_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"social_post_analytics_snapshots\\" (\\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 \\"social_post_id\\" UUID,\\n \\"platform\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"raw\\" JSON,\\n \\"captured_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_post_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_posts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"platform":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"raw":{"type":"JSON","notNull":false},"captured_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_post_analytics_snapshots_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_post_analytics_snapshots_meta_type_idx","columns":["_meta_type"]},{"name":"social_post_analytics_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_post_analytics_snapshots_social_post_id_idx","columns":["social_post_id"]}],"version":"bd17983d"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPost":{"name":"socialpost","className":"SocialPost","qualifiedName":"@happyvertical/smrt-social:SocialPost","collection":"socialposts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/social-post.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"socialAccountId":{"type":"foreignKey","required":false,"related":"SocialAccount"},"createdByUserId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-users:User"},"videoContentId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-video:VideoContent"},"contentId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-content:Content"},"postType":{"type":"text","required":false,"default":"text"},"mediaUrl":{"type":"text","required":false},"title":{"type":"text","required":false},"description":{"type":"text","required":false,"default":""},"hashtags":{"type":"json","required":false,"default":[]},"linkUrl":{"type":"text","required":false},"platformPostId":{"type":"text","required":false},"platformUrl":{"type":"text","required":false},"scheduledAt":{"type":"datetime","required":false},"publishedAt":{"type":"datetime","required":false},"status":{"type":"text","required":false,"default":"draft"},"errorMessage":{"type":"text","required":false},"analytics":{"type":"json","required":false},"analyticsLastSyncedAt":{"type":"datetime","required":false}},"methods":{},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get"]},"cli":true,"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"SocialPost","collectionExportName":"SocialPostCollection","schema":{"tableName":"social_posts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_posts\\" (\\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 \\"social_account_id\\" UUID,\\n \\"created_by_user_id\\" UUID,\\n \\"video_content_id\\" UUID,\\n \\"content_id\\" UUID,\\n \\"post_type\\" TEXT DEFAULT 'text',\\n \\"media_url\\" TEXT,\\n \\"title\\" TEXT,\\n \\"description\\" TEXT DEFAULT '',\\n \\"hashtags\\" JSON DEFAULT '[]',\\n \\"link_url\\" TEXT,\\n \\"platform_post_id\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"scheduled_at\\" TIMESTAMP,\\n \\"published_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"error_message\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"analytics_last_synced_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_account_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_accounts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"created_by_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"video_content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"post_type":{"type":"TEXT","notNull":false,"default":"text"},"media_url":{"type":"TEXT","notNull":false},"title":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false,"default":""},"hashtags":{"type":"JSON","notNull":false,"default":[]},"link_url":{"type":"TEXT","notNull":false},"platform_post_id":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"scheduled_at":{"type":"TIMESTAMP","notNull":false},"published_at":{"type":"TIMESTAMP","notNull":false},"status":{"type":"TEXT","notNull":false,"default":"draft"},"error_message":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"analytics_last_synced_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_posts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_posts_meta_type_idx","columns":["_meta_type"]},{"name":"social_posts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_posts_social_account_id_idx","columns":["social_account_id"]},{"name":"social_posts_created_by_user_id_idx","columns":["created_by_user_id"]},{"name":"social_posts_video_content_id_idx","columns":["video_content_id"]},{"name":"social_posts_content_id_idx","columns":["content_id"]}],"version":"cfb50b15"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:OAuthStateCollection":{"name":"oauthstatecollection","className":"OAuthStateCollection","qualifiedName":"@happyvertical/smrt-social:OAuthStateCollection","collection":"oauthstates","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/oauth-state-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"findByState":{"name":"findByState","async":true,"parameters":[{"name":"state","type":"string","optional":false}],"returnType":"Promise<OAuthState | null>","isStatic":false,"isPublic":true},"findExpired":{"name":"findExpired","async":true,"parameters":[{"name":"now","type":"Date","optional":true}],"returnType":"Promise<OAuthState[]>","isStatic":false,"isPublic":true},"deleteExpired":{"name":"deleteExpired","async":true,"parameters":[{"name":"now","type":"Date","optional":true}],"returnType":"Promise<number>","isStatic":false,"isPublic":true}},"decoratorConfig":{"mcp":false},"extends":"SmrtCollection","extendsTypeArg":"OAuthState","exportName":"OAuthStateCollection","collectionExportName":"OAuthStateCollectionCollection","schema":{"tableName":"oauth_states","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);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"state":{"type":"TEXT","notNull":false,"default":""},"code_verifier":{"type":"TEXT","notNull":false},"redirect_uri":{"type":"TEXT","notNull":false,"default":""},"scopes":{"type":"JSON","notNull":false,"default":[]},"expires_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"oauth_states_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"oauth_states_meta_type_idx","columns":["_meta_type"]},{"name":"oauth_states_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"709e111f"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialAccountCollection":{"name":"socialaccountcollection","className":"SocialAccountCollection","qualifiedName":"@happyvertical/smrt-social:SocialAccountCollection","collection":"socialaccounts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/social-account-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"findActive":{"name":"findActive","async":true,"parameters":[{"name":"platform","type":"SocialPlatformType","optional":true}],"returnType":"Promise<SocialAccount[]>","isStatic":false,"isPublic":true},"findReady":{"name":"findReady","async":true,"parameters":[{"name":"platform","type":"SocialPlatformType","optional":true}],"returnType":"Promise<SocialAccount[]>","isStatic":false,"isPublic":true},"findNeedsAttention":{"name":"findNeedsAttention","async":true,"parameters":[],"returnType":"Promise<SocialAccount[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{},"extends":"SmrtCollection","extendsTypeArg":"SocialAccount","exportName":"SocialAccountCollection","collectionExportName":"SocialAccountCollectionCollection","schema":{"tableName":"social_accounts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_accounts\\" (\\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 \\"name\\" TEXT DEFAULT '',\\n \\"platform\\" TEXT DEFAULT 'youtube',\\n \\"platform_user_id\\" TEXT,\\n \\"platform_username\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"access_token\\" TEXT,\\n \\"refresh_token\\" TEXT,\\n \\"credential_secret_id\\" TEXT,\\n \\"access_token_secret_name\\" TEXT,\\n \\"refresh_token_secret_name\\" TEXT,\\n \\"token_expires_at\\" TIMESTAMP,\\n \\"is_active\\" BOOLEAN DEFAULT TRUE,\\n \\"default_hashtags\\" JSON DEFAULT '[]',\\n \\"scopes\\" JSON DEFAULT '[]',\\n \\"missing_permissions\\" JSON DEFAULT '[]',\\n \\"link_behavior\\" TEXT DEFAULT 'description',\\n \\"publish_mode\\" TEXT DEFAULT 'dry_run',\\n \\"public_publishing_allowed\\" BOOLEAN DEFAULT FALSE,\\n \\"status\\" TEXT DEFAULT 'connected',\\n \\"error_message\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"name":{"type":"TEXT","notNull":false,"default":""},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"platform_user_id":{"type":"TEXT","notNull":false},"platform_username":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"access_token":{"type":"TEXT","notNull":false},"refresh_token":{"type":"TEXT","notNull":false},"credential_secret_id":{"type":"TEXT","notNull":false},"access_token_secret_name":{"type":"TEXT","notNull":false},"refresh_token_secret_name":{"type":"TEXT","notNull":false},"token_expires_at":{"type":"TIMESTAMP","notNull":false},"is_active":{"type":"BOOLEAN","notNull":false,"default":true},"default_hashtags":{"type":"JSON","notNull":false,"default":[]},"scopes":{"type":"JSON","notNull":false,"default":[]},"missing_permissions":{"type":"JSON","notNull":false,"default":[]},"link_behavior":{"type":"TEXT","notNull":false,"default":"description"},"publish_mode":{"type":"TEXT","notNull":false,"default":"dry_run"},"public_publishing_allowed":{"type":"BOOLEAN","notNull":false,"default":false},"status":{"type":"TEXT","notNull":false,"default":"connected"},"error_message":{"type":"TEXT","notNull":false}},"indexes":[{"name":"social_accounts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_accounts_meta_type_idx","columns":["_meta_type"]},{"name":"social_accounts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"0c175da6"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPostAnalyticsSnapshotCollection":{"name":"socialpostanalyticssnapshotcollection","className":"SocialPostAnalyticsSnapshotCollection","qualifiedName":"@happyvertical/smrt-social:SocialPostAnalyticsSnapshotCollection","collection":"socialpostanalyticssnapshots","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/social-post-analytics-snapshot-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"recordSnapshot":{"name":"recordSnapshot","async":true,"parameters":[{"name":"options","type":"object","optional":false,"memberTypes":["string","SocialPlatformType","PostAnalytics","RawAnalyticsPayload","Date","string | null"]}],"returnType":"Promise<SocialPostAnalyticsSnapshot>","isStatic":false,"isPublic":true},"findForPost":{"name":"findForPost","async":true,"parameters":[{"name":"socialPostId","type":"string","optional":false}],"returnType":"Promise<SocialPostAnalyticsSnapshot[]>","isStatic":false,"isPublic":true},"findLatestForPost":{"name":"findLatestForPost","async":true,"parameters":[{"name":"socialPostId","type":"string","optional":false}],"returnType":"Promise<SocialPostAnalyticsSnapshot | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{},"extends":"SmrtCollection","extendsTypeArg":"SocialPostAnalyticsSnapshot","exportName":"SocialPostAnalyticsSnapshotCollection","collectionExportName":"SocialPostAnalyticsSnapshotCollectionCollection","schema":{"tableName":"social_post_analytics_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"social_post_analytics_snapshots\\" (\\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 \\"social_post_id\\" UUID,\\n \\"platform\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"raw\\" JSON,\\n \\"captured_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_post_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_posts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"platform":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"raw":{"type":"JSON","notNull":false},"captured_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_post_analytics_snapshots_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_post_analytics_snapshots_meta_type_idx","columns":["_meta_type"]},{"name":"social_post_analytics_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_post_analytics_snapshots_social_post_id_idx","columns":["social_post_id"]}],"version":"bd17983d"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPostCollection":{"name":"socialpostcollection","className":"SocialPostCollection","qualifiedName":"@happyvertical/smrt-social:SocialPostCollection","collection":"socialposts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/social-post-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"createDraft":{"name":"createDraft","async":true,"parameters":[{"name":"options","type":"CreateSocialPostDraftOptions","optional":false}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true},"findByStatus":{"name":"findByStatus","async":true,"parameters":[{"name":"status","type":"PostStatus","optional":false}],"returnType":"Promise<SocialPost[]>","isStatic":false,"isPublic":true},"findForAccount":{"name":"findForAccount","async":true,"parameters":[{"name":"socialAccountId","type":"string","optional":false}],"returnType":"Promise<SocialPost[]>","isStatic":false,"isPublic":true},"findDueForPublish":{"name":"findDueForPublish","async":true,"parameters":[{"name":"now","type":"Date","optional":true}],"returnType":"Promise<SocialPost[]>","isStatic":false,"isPublic":true},"recordPublishSuccess":{"name":"recordPublishSuccess","async":true,"parameters":[{"name":"post","type":"SocialPost","optional":false},{"name":"data","type":"PublishSuccessData","optional":false}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true},"recordPublishFailure":{"name":"recordPublishFailure","async":true,"parameters":[{"name":"post","type":"SocialPost","optional":false},{"name":"error","type":"Error | string","optional":false,"unionBranches":[{"type":"Error"},{"type":"string"}]}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true},"updateLatestAnalytics":{"name":"updateLatestAnalytics","async":true,"parameters":[{"name":"post","type":"SocialPost","optional":false},{"name":"analytics","type":"PostAnalytics","optional":false},{"name":"syncedAt","type":"Date","optional":true}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true}},"decoratorConfig":{},"extends":"SmrtCollection","extendsTypeArg":"SocialPost","exportName":"SocialPostCollection","collectionExportName":"SocialPostCollectionCollection","schema":{"tableName":"social_posts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_posts\\" (\\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 \\"social_account_id\\" UUID,\\n \\"created_by_user_id\\" UUID,\\n \\"video_content_id\\" UUID,\\n \\"content_id\\" UUID,\\n \\"post_type\\" TEXT DEFAULT 'text',\\n \\"media_url\\" TEXT,\\n \\"title\\" TEXT,\\n \\"description\\" TEXT DEFAULT '',\\n \\"hashtags\\" JSON DEFAULT '[]',\\n \\"link_url\\" TEXT,\\n \\"platform_post_id\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"scheduled_at\\" TIMESTAMP,\\n \\"published_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"error_message\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"analytics_last_synced_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_account_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_accounts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"created_by_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"video_content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"post_type":{"type":"TEXT","notNull":false,"default":"text"},"media_url":{"type":"TEXT","notNull":false},"title":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false,"default":""},"hashtags":{"type":"JSON","notNull":false,"default":[]},"link_url":{"type":"TEXT","notNull":false},"platform_post_id":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"scheduled_at":{"type":"TIMESTAMP","notNull":false},"published_at":{"type":"TIMESTAMP","notNull":false},"status":{"type":"TEXT","notNull":false,"default":"draft"},"error_message":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"analytics_last_synced_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_posts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_posts_meta_type_idx","columns":["_meta_type"]},{"name":"social_posts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_posts_social_account_id_idx","columns":["social_account_id"]},{"name":"social_posts_created_by_user_id_idx","columns":["created_by_user_id"]},{"name":"social_posts_video_content_id_idx","columns":["video_content_id"]},{"name":"social_posts_content_id_idx","columns":["content_id"]}],"version":"cfb50b15"},"importPath":"@happyvertical/smrt-social"}},"moduleType":"smrt","smrtDependencies":["@happyvertical/smrt-content","@happyvertical/smrt-core","@happyvertical/smrt-secrets","@happyvertical/smrt-tenancy","@happyvertical/smrt-video"],"stampsConstructors":true}`));
7
+ ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-social","packageVersion":"0.55.0","objects":{"@happyvertical/smrt-social:OAuthState":{"name":"oauthstate","className":"OAuthState","qualifiedName":"@happyvertical/smrt-social:OAuthState","collection":"oauthstates","filePath":"/home/runner/work/smrt/smrt/packages/social/src/oauth-state.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"platform":{"type":"text","required":false,"default":"youtube"},"state":{"type":"text","required":false,"default":""},"codeVerifier":{"type":"text","required":false},"redirectUri":{"type":"text","required":false,"default":""},"scopes":{"type":"json","required":false,"default":[]},"expiresAt":{"type":"datetime","required":false},"createdByUserId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-users:User"},"returnTo":{"type":"text","required":false}},"methods":{"verifyState":{"name":"verifyState","async":false,"parameters":[{"name":"callbackState","type":"string","optional":false}],"returnType":"boolean","isStatic":false,"isPublic":true},"generateState":{"name":"generateState","async":false,"parameters":[],"returnType":"string","isStatic":true,"isPublic":true},"generateCodeVerifier":{"name":"generateCodeVerifier","async":false,"parameters":[],"returnType":"string","isStatic":true,"isPublic":true},"generateCodeChallenge":{"name":"generateCodeChallenge","async":true,"parameters":[{"name":"verifier","type":"string","optional":false}],"returnType":"Promise<string>","isStatic":true,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","delete"]},"mcp":false,"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"OAuthState","collectionExportName":"OAuthStateCollection","schema":{"tableName":"oauth_states","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);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"state":{"type":"TEXT","notNull":false,"default":""},"code_verifier":{"type":"TEXT","notNull":false},"redirect_uri":{"type":"TEXT","notNull":false,"default":""},"scopes":{"type":"JSON","notNull":false,"default":[]},"expires_at":{"type":"TIMESTAMP","notNull":false},"created_by_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"return_to":{"type":"TEXT","notNull":false}},"indexes":[{"name":"oauth_states_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"oauth_states_meta_type_idx","columns":["_meta_type"]},{"name":"oauth_states_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"oauth_states_created_by_user_id_idx","columns":["created_by_user_id"]}],"version":"ca0ff7c5"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialAccount":{"name":"socialaccount","className":"SocialAccount","qualifiedName":"@happyvertical/smrt-social:SocialAccount","collection":"socialaccounts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/social-account.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"name":{"type":"text","required":false,"default":""},"platform":{"type":"text","required":false,"default":"youtube"},"platformUserId":{"type":"text","required":false},"platformUsername":{"type":"text","required":false},"platformUrl":{"type":"text","required":false},"accessToken":{"type":"text","required":false},"refreshToken":{"type":"text","required":false},"credentialSecretId":{"type":"text","required":false},"accessTokenSecretName":{"type":"text","required":false},"refreshTokenSecretName":{"type":"text","required":false},"tokenExpiresAt":{"type":"datetime","required":false},"isActive":{"type":"boolean","required":false,"default":true},"defaultHashtags":{"type":"json","required":false,"default":[]},"scopes":{"type":"json","required":false,"default":[]},"missingPermissions":{"type":"json","required":false,"default":[]},"linkBehavior":{"type":"text","required":false,"default":"description"},"publishMode":{"type":"text","required":false,"default":"dry_run"},"publicPublishingAllowed":{"type":"boolean","required":false,"default":false},"status":{"type":"text","required":false,"default":"connected"},"errorMessage":{"type":"text","required":false}},"methods":{"getSlug":{"name":"getSlug","async":true,"parameters":[],"returnType":"Promise<string | null | undefined>","isStatic":false,"isPublic":true},"setCredentials":{"name":"setCredentials","async":true,"parameters":[{"name":"credentials","type":"Record<string, unknown>","optional":false},{"name":"options","type":"object","optional":true,"memberTypes":["string"]}],"returnType":"Promise<void>","isStatic":false,"isPublic":true},"getCredentials":{"name":"getCredentials","async":true,"parameters":[],"returnType":"Promise<Record<string, unknown> | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get"]},"cli":{"skipApiCheck":true},"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"SocialAccount","collectionExportName":"SocialAccountCollection","schema":{"tableName":"social_accounts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_accounts\\" (\\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 \\"name\\" TEXT DEFAULT '',\\n \\"platform\\" TEXT DEFAULT 'youtube',\\n \\"platform_user_id\\" TEXT,\\n \\"platform_username\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"access_token\\" TEXT,\\n \\"refresh_token\\" TEXT,\\n \\"credential_secret_id\\" TEXT,\\n \\"access_token_secret_name\\" TEXT,\\n \\"refresh_token_secret_name\\" TEXT,\\n \\"token_expires_at\\" TIMESTAMP,\\n \\"is_active\\" BOOLEAN DEFAULT TRUE,\\n \\"default_hashtags\\" JSON DEFAULT '[]',\\n \\"scopes\\" JSON DEFAULT '[]',\\n \\"missing_permissions\\" JSON DEFAULT '[]',\\n \\"link_behavior\\" TEXT DEFAULT 'description',\\n \\"publish_mode\\" TEXT DEFAULT 'dry_run',\\n \\"public_publishing_allowed\\" BOOLEAN DEFAULT FALSE,\\n \\"status\\" TEXT DEFAULT 'connected',\\n \\"error_message\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"name":{"type":"TEXT","notNull":false,"default":""},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"platform_user_id":{"type":"TEXT","notNull":false},"platform_username":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"access_token":{"type":"TEXT","notNull":false},"refresh_token":{"type":"TEXT","notNull":false},"credential_secret_id":{"type":"TEXT","notNull":false},"access_token_secret_name":{"type":"TEXT","notNull":false},"refresh_token_secret_name":{"type":"TEXT","notNull":false},"token_expires_at":{"type":"TIMESTAMP","notNull":false},"is_active":{"type":"BOOLEAN","notNull":false,"default":true},"default_hashtags":{"type":"JSON","notNull":false,"default":[]},"scopes":{"type":"JSON","notNull":false,"default":[]},"missing_permissions":{"type":"JSON","notNull":false,"default":[]},"link_behavior":{"type":"TEXT","notNull":false,"default":"description"},"publish_mode":{"type":"TEXT","notNull":false,"default":"dry_run"},"public_publishing_allowed":{"type":"BOOLEAN","notNull":false,"default":false},"status":{"type":"TEXT","notNull":false,"default":"connected"},"error_message":{"type":"TEXT","notNull":false}},"indexes":[{"name":"social_accounts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_accounts_meta_type_idx","columns":["_meta_type"]},{"name":"social_accounts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"0c175da6"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPostAnalyticsSnapshot":{"name":"socialpostanalyticssnapshot","className":"SocialPostAnalyticsSnapshot","qualifiedName":"@happyvertical/smrt-social:SocialPostAnalyticsSnapshot","collection":"socialpostanalyticssnapshots","filePath":"/home/runner/work/smrt/smrt/packages/social/src/social-post-analytics-snapshot.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"socialPostId":{"type":"foreignKey","required":false,"related":"SocialPost"},"platform":{"type":"text","required":true,"_meta":{"required":true}},"analytics":{"type":"json","required":false},"raw":{"type":"json","required":false,"_meta":{"nullable":true}},"capturedAt":{"type":"datetime","required":false}},"methods":{},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","delete"]},"mcp":{"include":["list","get"]},"cli":true,"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"SocialPostAnalyticsSnapshot","collectionExportName":"SocialPostAnalyticsSnapshotCollection","validationRules":[{"field":"platform","rule":"required","fieldType":"text"}],"schema":{"tableName":"social_post_analytics_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"social_post_analytics_snapshots\\" (\\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 \\"social_post_id\\" UUID,\\n \\"platform\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"raw\\" JSON,\\n \\"captured_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_post_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_posts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"platform":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"raw":{"type":"JSON","notNull":false},"captured_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_post_analytics_snapshots_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_post_analytics_snapshots_meta_type_idx","columns":["_meta_type"]},{"name":"social_post_analytics_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_post_analytics_snapshots_social_post_id_idx","columns":["social_post_id"]}],"version":"bd17983d"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPost":{"name":"socialpost","className":"SocialPost","qualifiedName":"@happyvertical/smrt-social:SocialPost","collection":"socialposts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/social-post.ts","packageName":"@happyvertical/smrt-social","fields":{"created_at":{"type":"datetime","required":false},"updated_at":{"type":"datetime","required":false},"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"socialAccountId":{"type":"foreignKey","required":false,"related":"SocialAccount"},"createdByUserId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-users:User"},"videoContentId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-video:VideoContent"},"contentId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-content:Content"},"postType":{"type":"text","required":false,"default":"text"},"mediaUrl":{"type":"text","required":false},"title":{"type":"text","required":false},"description":{"type":"text","required":false,"default":""},"hashtags":{"type":"json","required":false,"default":[]},"linkUrl":{"type":"text","required":false},"platformPostId":{"type":"text","required":false},"platformUrl":{"type":"text","required":false},"scheduledAt":{"type":"datetime","required":false},"publishedAt":{"type":"datetime","required":false},"status":{"type":"text","required":false,"default":"draft"},"errorMessage":{"type":"text","required":false},"analytics":{"type":"json","required":false},"analyticsLastSyncedAt":{"type":"datetime","required":false}},"methods":{},"decoratorConfig":{"tableStrategy":"sti","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get"]},"cli":true,"tenantScoped":{"mode":"optional"},"conflictColumns":["tenant_id","slug","context","_meta_type"]},"extends":"SmrtObject","exportName":"SocialPost","collectionExportName":"SocialPostCollection","schema":{"tableName":"social_posts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_posts\\" (\\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 \\"social_account_id\\" UUID,\\n \\"created_by_user_id\\" UUID,\\n \\"video_content_id\\" UUID,\\n \\"content_id\\" UUID,\\n \\"post_type\\" TEXT DEFAULT 'text',\\n \\"media_url\\" TEXT,\\n \\"title\\" TEXT,\\n \\"description\\" TEXT DEFAULT '',\\n \\"hashtags\\" JSON DEFAULT '[]',\\n \\"link_url\\" TEXT,\\n \\"platform_post_id\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"scheduled_at\\" TIMESTAMP,\\n \\"published_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"error_message\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"analytics_last_synced_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_account_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_accounts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"created_by_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"video_content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"post_type":{"type":"TEXT","notNull":false,"default":"text"},"media_url":{"type":"TEXT","notNull":false},"title":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false,"default":""},"hashtags":{"type":"JSON","notNull":false,"default":[]},"link_url":{"type":"TEXT","notNull":false},"platform_post_id":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"scheduled_at":{"type":"TIMESTAMP","notNull":false},"published_at":{"type":"TIMESTAMP","notNull":false},"status":{"type":"TEXT","notNull":false,"default":"draft"},"error_message":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"analytics_last_synced_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_posts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_posts_meta_type_idx","columns":["_meta_type"]},{"name":"social_posts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_posts_social_account_id_idx","columns":["social_account_id"]},{"name":"social_posts_created_by_user_id_idx","columns":["created_by_user_id"]},{"name":"social_posts_video_content_id_idx","columns":["video_content_id"]},{"name":"social_posts_content_id_idx","columns":["content_id"]}],"version":"cfb50b15"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:OAuthStateCollection":{"name":"oauthstatecollection","className":"OAuthStateCollection","qualifiedName":"@happyvertical/smrt-social:OAuthStateCollection","collection":"oauthstates","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/oauth-state-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"findByState":{"name":"findByState","async":true,"parameters":[{"name":"state","type":"string","optional":false}],"returnType":"Promise<OAuthState | null>","isStatic":false,"isPublic":true},"consume":{"name":"consume","async":true,"parameters":[{"name":"state","type":"OAuthState","optional":false}],"returnType":"Promise<boolean>","isStatic":false,"isPublic":true},"findExpired":{"name":"findExpired","async":true,"parameters":[{"name":"now","type":"Date","optional":true}],"returnType":"Promise<OAuthState[]>","isStatic":false,"isPublic":true},"deleteExpired":{"name":"deleteExpired","async":true,"parameters":[{"name":"now","type":"Date","optional":true}],"returnType":"Promise<number>","isStatic":false,"isPublic":true}},"decoratorConfig":{"mcp":false},"extends":"SmrtCollection","extendsTypeArg":"OAuthState","exportName":"OAuthStateCollection","collectionExportName":"OAuthStateCollectionCollection","schema":{"tableName":"oauth_states","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);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"state":{"type":"TEXT","notNull":false,"default":""},"code_verifier":{"type":"TEXT","notNull":false},"redirect_uri":{"type":"TEXT","notNull":false,"default":""},"scopes":{"type":"JSON","notNull":false,"default":[]},"expires_at":{"type":"TIMESTAMP","notNull":false},"created_by_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"return_to":{"type":"TEXT","notNull":false}},"indexes":[{"name":"oauth_states_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"oauth_states_meta_type_idx","columns":["_meta_type"]},{"name":"oauth_states_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"oauth_states_created_by_user_id_idx","columns":["created_by_user_id"]}],"version":"ca0ff7c5"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialAccountCollection":{"name":"socialaccountcollection","className":"SocialAccountCollection","qualifiedName":"@happyvertical/smrt-social:SocialAccountCollection","collection":"socialaccounts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/social-account-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"findActive":{"name":"findActive","async":true,"parameters":[{"name":"platform","type":"SocialPlatformType","optional":true}],"returnType":"Promise<SocialAccount[]>","isStatic":false,"isPublic":true},"findReady":{"name":"findReady","async":true,"parameters":[{"name":"platform","type":"SocialPlatformType","optional":true}],"returnType":"Promise<SocialAccount[]>","isStatic":false,"isPublic":true},"findNeedsAttention":{"name":"findNeedsAttention","async":true,"parameters":[],"returnType":"Promise<SocialAccount[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{},"extends":"SmrtCollection","extendsTypeArg":"SocialAccount","exportName":"SocialAccountCollection","collectionExportName":"SocialAccountCollectionCollection","schema":{"tableName":"social_accounts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_accounts\\" (\\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 \\"name\\" TEXT DEFAULT '',\\n \\"platform\\" TEXT DEFAULT 'youtube',\\n \\"platform_user_id\\" TEXT,\\n \\"platform_username\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"access_token\\" TEXT,\\n \\"refresh_token\\" TEXT,\\n \\"credential_secret_id\\" TEXT,\\n \\"access_token_secret_name\\" TEXT,\\n \\"refresh_token_secret_name\\" TEXT,\\n \\"token_expires_at\\" TIMESTAMP,\\n \\"is_active\\" BOOLEAN DEFAULT TRUE,\\n \\"default_hashtags\\" JSON DEFAULT '[]',\\n \\"scopes\\" JSON DEFAULT '[]',\\n \\"missing_permissions\\" JSON DEFAULT '[]',\\n \\"link_behavior\\" TEXT DEFAULT 'description',\\n \\"publish_mode\\" TEXT DEFAULT 'dry_run',\\n \\"public_publishing_allowed\\" BOOLEAN DEFAULT FALSE,\\n \\"status\\" TEXT DEFAULT 'connected',\\n \\"error_message\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"name":{"type":"TEXT","notNull":false,"default":""},"platform":{"type":"TEXT","notNull":false,"default":"youtube"},"platform_user_id":{"type":"TEXT","notNull":false},"platform_username":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"access_token":{"type":"TEXT","notNull":false},"refresh_token":{"type":"TEXT","notNull":false},"credential_secret_id":{"type":"TEXT","notNull":false},"access_token_secret_name":{"type":"TEXT","notNull":false},"refresh_token_secret_name":{"type":"TEXT","notNull":false},"token_expires_at":{"type":"TIMESTAMP","notNull":false},"is_active":{"type":"BOOLEAN","notNull":false,"default":true},"default_hashtags":{"type":"JSON","notNull":false,"default":[]},"scopes":{"type":"JSON","notNull":false,"default":[]},"missing_permissions":{"type":"JSON","notNull":false,"default":[]},"link_behavior":{"type":"TEXT","notNull":false,"default":"description"},"publish_mode":{"type":"TEXT","notNull":false,"default":"dry_run"},"public_publishing_allowed":{"type":"BOOLEAN","notNull":false,"default":false},"status":{"type":"TEXT","notNull":false,"default":"connected"},"error_message":{"type":"TEXT","notNull":false}},"indexes":[{"name":"social_accounts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_accounts_meta_type_idx","columns":["_meta_type"]},{"name":"social_accounts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"0c175da6"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPostAnalyticsSnapshotCollection":{"name":"socialpostanalyticssnapshotcollection","className":"SocialPostAnalyticsSnapshotCollection","qualifiedName":"@happyvertical/smrt-social:SocialPostAnalyticsSnapshotCollection","collection":"socialpostanalyticssnapshots","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/social-post-analytics-snapshot-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"recordSnapshot":{"name":"recordSnapshot","async":true,"parameters":[{"name":"options","type":"object","optional":false,"memberTypes":["string","SocialPlatformType","PostAnalytics","RawAnalyticsPayload","Date","string | null"]}],"returnType":"Promise<SocialPostAnalyticsSnapshot>","isStatic":false,"isPublic":true},"findForPost":{"name":"findForPost","async":true,"parameters":[{"name":"socialPostId","type":"string","optional":false}],"returnType":"Promise<SocialPostAnalyticsSnapshot[]>","isStatic":false,"isPublic":true},"findLatestForPost":{"name":"findLatestForPost","async":true,"parameters":[{"name":"socialPostId","type":"string","optional":false}],"returnType":"Promise<SocialPostAnalyticsSnapshot | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{},"extends":"SmrtCollection","extendsTypeArg":"SocialPostAnalyticsSnapshot","exportName":"SocialPostAnalyticsSnapshotCollection","collectionExportName":"SocialPostAnalyticsSnapshotCollectionCollection","schema":{"tableName":"social_post_analytics_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"social_post_analytics_snapshots\\" (\\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 \\"social_post_id\\" UUID,\\n \\"platform\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"raw\\" JSON,\\n \\"captured_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_post_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_posts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"platform":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"raw":{"type":"JSON","notNull":false},"captured_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_post_analytics_snapshots_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_post_analytics_snapshots_meta_type_idx","columns":["_meta_type"]},{"name":"social_post_analytics_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_post_analytics_snapshots_social_post_id_idx","columns":["social_post_id"]}],"version":"bd17983d"},"importPath":"@happyvertical/smrt-social"},"@happyvertical/smrt-social:SocialPostCollection":{"name":"socialpostcollection","className":"SocialPostCollection","qualifiedName":"@happyvertical/smrt-social:SocialPostCollection","collection":"socialposts","filePath":"/home/runner/work/smrt/smrt/packages/social/src/collections/social-post-collection.ts","packageName":"@happyvertical/smrt-social","fields":{},"methods":{"createDraft":{"name":"createDraft","async":true,"parameters":[{"name":"options","type":"CreateSocialPostDraftOptions","optional":false}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true},"findByStatus":{"name":"findByStatus","async":true,"parameters":[{"name":"status","type":"PostStatus","optional":false}],"returnType":"Promise<SocialPost[]>","isStatic":false,"isPublic":true},"findForAccount":{"name":"findForAccount","async":true,"parameters":[{"name":"socialAccountId","type":"string","optional":false}],"returnType":"Promise<SocialPost[]>","isStatic":false,"isPublic":true},"findDueForPublish":{"name":"findDueForPublish","async":true,"parameters":[{"name":"now","type":"Date","optional":true}],"returnType":"Promise<SocialPost[]>","isStatic":false,"isPublic":true},"recordPublishSuccess":{"name":"recordPublishSuccess","async":true,"parameters":[{"name":"post","type":"SocialPost","optional":false},{"name":"data","type":"PublishSuccessData","optional":false}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true},"recordPublishFailure":{"name":"recordPublishFailure","async":true,"parameters":[{"name":"post","type":"SocialPost","optional":false},{"name":"error","type":"Error | string","optional":false,"unionBranches":[{"type":"Error"},{"type":"string"}]}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true},"updateLatestAnalytics":{"name":"updateLatestAnalytics","async":true,"parameters":[{"name":"post","type":"SocialPost","optional":false},{"name":"analytics","type":"PostAnalytics","optional":false},{"name":"syncedAt","type":"Date","optional":true}],"returnType":"Promise<SocialPost>","isStatic":false,"isPublic":true}},"decoratorConfig":{},"extends":"SmrtCollection","extendsTypeArg":"SocialPost","exportName":"SocialPostCollection","collectionExportName":"SocialPostCollectionCollection","schema":{"tableName":"social_posts","ddl":"CREATE TABLE IF NOT EXISTS \\"social_posts\\" (\\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 \\"social_account_id\\" UUID,\\n \\"created_by_user_id\\" UUID,\\n \\"video_content_id\\" UUID,\\n \\"content_id\\" UUID,\\n \\"post_type\\" TEXT DEFAULT 'text',\\n \\"media_url\\" TEXT,\\n \\"title\\" TEXT,\\n \\"description\\" TEXT DEFAULT '',\\n \\"hashtags\\" JSON DEFAULT '[]',\\n \\"link_url\\" TEXT,\\n \\"platform_post_id\\" TEXT,\\n \\"platform_url\\" TEXT,\\n \\"scheduled_at\\" TIMESTAMP,\\n \\"published_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"error_message\\" TEXT,\\n \\"analytics\\" JSON,\\n \\"analytics_last_synced_at\\" TIMESTAMP\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"_meta_type":{"type":"TEXT","notNull":true},"_meta_data":{"type":"JSON","notNull":false},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false},"social_account_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"foreignKey":{"table":"social_accounts","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"created_by_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"video_content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"content_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false},"post_type":{"type":"TEXT","notNull":false,"default":"text"},"media_url":{"type":"TEXT","notNull":false},"title":{"type":"TEXT","notNull":false},"description":{"type":"TEXT","notNull":false,"default":""},"hashtags":{"type":"JSON","notNull":false,"default":[]},"link_url":{"type":"TEXT","notNull":false},"platform_post_id":{"type":"TEXT","notNull":false},"platform_url":{"type":"TEXT","notNull":false},"scheduled_at":{"type":"TIMESTAMP","notNull":false},"published_at":{"type":"TIMESTAMP","notNull":false},"status":{"type":"TEXT","notNull":false,"default":"draft"},"error_message":{"type":"TEXT","notNull":false},"analytics":{"type":"JSON","notNull":false},"analytics_last_synced_at":{"type":"TIMESTAMP","notNull":false}},"indexes":[{"name":"social_posts_slug_context_meta_type_idx","columns":["tenant_id","slug","context","_meta_type"],"unique":true,"nullsNotDistinct":true},{"name":"social_posts_meta_type_idx","columns":["_meta_type"]},{"name":"social_posts_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"social_posts_social_account_id_idx","columns":["social_account_id"]},{"name":"social_posts_created_by_user_id_idx","columns":["created_by_user_id"]},{"name":"social_posts_video_content_id_idx","columns":["video_content_id"]},{"name":"social_posts_content_id_idx","columns":["content_id"]}],"version":"cfb50b15"},"importPath":"@happyvertical/smrt-social"}},"moduleType":"smrt","smrtDependencies":["@happyvertical/smrt-content","@happyvertical/smrt-core","@happyvertical/smrt-secrets","@happyvertical/smrt-tenancy","@happyvertical/smrt-video"],"stampsConstructors":true}`));
8
8
  //#endregion
9
9
  //#region src/oauth-state.ts
10
10
  var __defProp$3 = Object.defineProperty;
@@ -52,6 +52,13 @@ var OAuthState = class extends SmrtObject {
52
52
  * States should be short-lived (10 minutes typical)
53
53
  */
54
54
  expiresAt = new Date(Date.now() + 600 * 1e3);
55
+ createdByUserId = null;
56
+ /**
57
+ * Application-defined path to return to after the callback, for example the
58
+ * settings page that started the flow. Opaque to the framework: the host
59
+ * that reads it must validate it as a same-origin path before redirecting.
60
+ */
61
+ returnTo = null;
55
62
  constructor(options = {}) {
56
63
  super(options);
57
64
  if (options.platform !== void 0) this.platform = options.platform;
@@ -61,6 +68,8 @@ var OAuthState = class extends SmrtObject {
61
68
  if (options.scopes !== void 0) this.scopes = options.scopes;
62
69
  if (options.expiresAt !== void 0) this.expiresAt = options.expiresAt;
63
70
  if (options.tenantId !== void 0) this.tenantId = options.tenantId;
71
+ if (options.createdByUserId !== void 0) this.createdByUserId = options.createdByUserId;
72
+ if (options.returnTo !== void 0) this.returnTo = options.returnTo;
64
73
  }
65
74
  /**
66
75
  * Check if the state has expired
@@ -107,6 +116,7 @@ var OAuthState = class extends SmrtObject {
107
116
  };
108
117
  __publicField$3(OAuthState, "__smrtPackage__", "@happyvertical/smrt-social");
109
118
  __decorateClass$3([tenantId({ nullable: true })], OAuthState.prototype, "tenantId", 2);
119
+ __decorateClass$3([crossPackageRef("@happyvertical/smrt-users:User")], OAuthState.prototype, "createdByUserId", 2);
110
120
  OAuthState = __decorateClass$3([TenantScoped({ mode: "optional" }), smrt({
111
121
  tableStrategy: "sti",
112
122
  api: { include: [
@@ -125,6 +135,25 @@ var OAuthStateCollection = class extends SmrtCollection {
125
135
  async findByState(state) {
126
136
  return this.get({ state });
127
137
  }
138
+ /**
139
+ * Consume a loaded state exactly once.
140
+ *
141
+ * Deletes the record with a revision-guarded delete, so when two callbacks
142
+ * race on the same state only one delete removes the row. Returns `true`
143
+ * for that caller and `false` for every caller whose row was already gone
144
+ * or changed; any other failure propagates. Call it before acting on the
145
+ * state (exchanging the code), and stop when it returns `false`.
146
+ */
147
+ async consume(state) {
148
+ if (!state.id || !state.updated_at) return false;
149
+ try {
150
+ await state.delete({ expectedUpdatedAt: state.updated_at });
151
+ return true;
152
+ } catch (error) {
153
+ if (error instanceof RuntimeError && error.code === "RUNTIME_REVISION_CONFLICT") return false;
154
+ throw error;
155
+ }
156
+ }
128
157
  async findExpired(now = /* @__PURE__ */ new Date()) {
129
158
  return this.list({
130
159
  where: { "expiresAt <=": now },