@withstudiocms/sdk 0.0.0-beta.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/dist/cache.d.ts +109 -0
  4. package/dist/cache.js +94 -0
  5. package/dist/consts.d.ts +37 -0
  6. package/dist/consts.js +35 -0
  7. package/dist/context.d.ts +208 -0
  8. package/dist/context.js +40 -0
  9. package/dist/errors.d.ts +9 -0
  10. package/dist/errors.js +6 -0
  11. package/dist/index.d.ts +1024 -0
  12. package/dist/index.js +24 -0
  13. package/dist/lib/diff.d.ts +39 -0
  14. package/dist/lib/diff.js +29 -0
  15. package/dist/lib/logger.d.ts +31 -0
  16. package/dist/lib/logger.js +131 -0
  17. package/dist/lib/pluginUtils.d.ts +222 -0
  18. package/dist/lib/pluginUtils.js +87 -0
  19. package/dist/lib/storage-manager.d.ts +10 -0
  20. package/dist/lib/storage-manager.js +17 -0
  21. package/dist/migrations/20251025T040912_init.d.ts +17 -0
  22. package/dist/migrations/20251025T040912_init.js +260 -0
  23. package/dist/migrations/20251130T150847_drop_deprecated.d.ts +13 -0
  24. package/dist/migrations/20251130T150847_drop_deprecated.js +262 -0
  25. package/dist/migrations/20251221T002125_url-mapping.d.ts +13 -0
  26. package/dist/migrations/20251221T002125_url-mapping.js +228 -0
  27. package/dist/migrator.d.ts +25 -0
  28. package/dist/migrator.js +21 -0
  29. package/dist/modules/auth/index.d.ts +419 -0
  30. package/dist/modules/auth/index.js +436 -0
  31. package/dist/modules/clear/index.d.ts +72 -0
  32. package/dist/modules/clear/index.js +52 -0
  33. package/dist/modules/config/consts.d.ts +32 -0
  34. package/dist/modules/config/consts.js +18 -0
  35. package/dist/modules/config/index.d.ts +100 -0
  36. package/dist/modules/config/index.js +224 -0
  37. package/dist/modules/config/templates/mailer.d.ts +36 -0
  38. package/dist/modules/config/templates/mailer.js +218 -0
  39. package/dist/modules/config/type-utils.d.ts +13 -0
  40. package/dist/modules/config/type-utils.js +11 -0
  41. package/dist/modules/delete/index.d.ts +141 -0
  42. package/dist/modules/delete/index.js +279 -0
  43. package/dist/modules/diffTracking/index.d.ts +188 -0
  44. package/dist/modules/diffTracking/index.js +277 -0
  45. package/dist/modules/get/index.d.ts +372 -0
  46. package/dist/modules/get/index.js +579 -0
  47. package/dist/modules/index.d.ts +883 -0
  48. package/dist/modules/index.js +37 -0
  49. package/dist/modules/init/index.d.ts +60 -0
  50. package/dist/modules/init/index.js +38 -0
  51. package/dist/modules/middleware/index.d.ts +56 -0
  52. package/dist/modules/middleware/index.js +50 -0
  53. package/dist/modules/notificationSettings/index.d.ts +57 -0
  54. package/dist/modules/notificationSettings/index.js +39 -0
  55. package/dist/modules/plugins/index.d.ts +167 -0
  56. package/dist/modules/plugins/index.js +272 -0
  57. package/dist/modules/post/index.d.ts +306 -0
  58. package/dist/modules/post/index.js +337 -0
  59. package/dist/modules/resetTokenBucket/index.d.ts +91 -0
  60. package/dist/modules/resetTokenBucket/index.js +96 -0
  61. package/dist/modules/rest_api/index.d.ts +92 -0
  62. package/dist/modules/rest_api/index.js +117 -0
  63. package/dist/modules/update/index.d.ts +184 -0
  64. package/dist/modules/update/index.js +192 -0
  65. package/dist/modules/util/collectors.d.ts +125 -0
  66. package/dist/modules/util/collectors.js +168 -0
  67. package/dist/modules/util/folderTree.d.ts +100 -0
  68. package/dist/modules/util/folderTree.js +176 -0
  69. package/dist/modules/util/generators.d.ts +83 -0
  70. package/dist/modules/util/generators.js +106 -0
  71. package/dist/modules/util/getFromNPM.d.ts +199 -0
  72. package/dist/modules/util/getFromNPM.js +106 -0
  73. package/dist/modules/util/index.d.ts +100 -0
  74. package/dist/modules/util/index.js +20 -0
  75. package/dist/modules/util/parsers.d.ts +60 -0
  76. package/dist/modules/util/parsers.js +43 -0
  77. package/dist/modules/util/slugify.d.ts +22 -0
  78. package/dist/modules/util/slugify.js +19 -0
  79. package/dist/modules/util/users.d.ts +99 -0
  80. package/dist/modules/util/users.js +78 -0
  81. package/dist/tables.d.ts +433 -0
  82. package/dist/tables.js +169 -0
  83. package/dist/types.d.ts +359 -0
  84. package/dist/types.js +10 -0
  85. package/package.json +67 -7
@@ -0,0 +1,117 @@
1
+ import { Effect, Schema } from "@withstudiocms/effect";
2
+ import { DBClientLive } from "../../context.js";
3
+ import { StudioCMSAPIKeys, StudioCMSPermissions } from "../../tables.js";
4
+ import { SDKGenerators } from "../util/generators.js";
5
+ const SDKRestAPIModule = Effect.gen(function* () {
6
+ const [{ withCodec, withEncoder }, { generateToken }] = yield* Effect.all([
7
+ DBClientLive,
8
+ SDKGenerators
9
+ ]);
10
+ const _getTokensForUser = withCodec({
11
+ encoder: Schema.String,
12
+ decoder: Schema.Array(StudioCMSAPIKeys.Select),
13
+ callbackFn: (db, userId) => db(
14
+ (client) => client.selectFrom("StudioCMSAPIKeys").selectAll().where("userId", "=", userId).execute()
15
+ )
16
+ });
17
+ const _newToken = withCodec({
18
+ encoder: StudioCMSAPIKeys.Insert,
19
+ decoder: StudioCMSAPIKeys.Select,
20
+ callbackFn: (db, tokenData) => db(
21
+ (client) => client.transaction().execute(async (trx) => {
22
+ await trx.insertInto("StudioCMSAPIKeys").values(tokenData).executeTakeFirstOrThrow();
23
+ return await trx.selectFrom("StudioCMSAPIKeys").selectAll().where("id", "=", tokenData.id).executeTakeFirstOrThrow();
24
+ })
25
+ )
26
+ });
27
+ const _deleteToken = withEncoder({
28
+ encoder: Schema.Struct({
29
+ userId: Schema.String,
30
+ tokenId: Schema.String
31
+ }),
32
+ callbackFn: (db, { userId, tokenId }) => db(
33
+ (client) => client.deleteFrom("StudioCMSAPIKeys").where("userId", "=", userId).where("id", "=", tokenId).execute()
34
+ )
35
+ });
36
+ const _getByKey = withCodec({
37
+ encoder: Schema.String,
38
+ decoder: Schema.UndefinedOr(StudioCMSAPIKeys.Select),
39
+ callbackFn: (db, key) => db(
40
+ (client) => client.selectFrom("StudioCMSAPIKeys").selectAll().where("key", "=", key).executeTakeFirst()
41
+ )
42
+ });
43
+ const _getKeyPermissions = withCodec({
44
+ encoder: Schema.String,
45
+ decoder: Schema.UndefinedOr(StudioCMSPermissions.Select),
46
+ callbackFn: (db, userId) => db(
47
+ (client) => client.selectFrom("StudioCMSPermissions").selectAll().where("user", "=", userId).executeTakeFirst()
48
+ )
49
+ });
50
+ const _createNewTokenForUser = Effect.fn(
51
+ (userId, description) => generateToken(userId, true).pipe(
52
+ Effect.flatMap(
53
+ (key) => _newToken({
54
+ id: crypto.randomUUID(),
55
+ key,
56
+ userId,
57
+ description,
58
+ creationDate: (/* @__PURE__ */ new Date()).toISOString()
59
+ })
60
+ )
61
+ )
62
+ );
63
+ const _verifyToken = Effect.fn(
64
+ (key) => Effect.gen(function* () {
65
+ const apiKeyRecord = yield* _getByKey(key);
66
+ if (!apiKeyRecord) return false;
67
+ const permissionsRecord = yield* _getKeyPermissions(apiKeyRecord.userId);
68
+ if (!permissionsRecord) return false;
69
+ return {
70
+ userId: apiKeyRecord.userId,
71
+ key: apiKeyRecord.key,
72
+ rank: permissionsRecord.rank
73
+ };
74
+ })
75
+ );
76
+ const tokens = {
77
+ /**
78
+ * Retrieves all API tokens for a specific user.
79
+ *
80
+ * @param userId - The ID of the user whose tokens are to be retrieved.
81
+ * @returns An Effect that resolves to an array of API keys for the user.
82
+ * @throws {LibSQLDatabaseError} If a database error occurs during the operation.
83
+ */
84
+ get: _getTokensForUser,
85
+ /**
86
+ * Creates a new API token for a user with the specified description.
87
+ *
88
+ * @param userId - The ID of the user for whom to create the token.
89
+ * @param description - A description for the API key.
90
+ * @returns An Effect that resolves to the created API key record.
91
+ * @throws {LibSQLDatabaseError} If a database error occurs during the operation.
92
+ */
93
+ new: _createNewTokenForUser,
94
+ /**
95
+ * Deletes an API token for a user by its ID.
96
+ *
97
+ * @param userId - The ID of the user whose token is to be deleted.
98
+ * @param tokenId - The ID of the API token to delete.
99
+ * @returns An Effect that resolves when the token is successfully deleted.
100
+ * @throws {LibSQLDatabaseError} If a database error occurs during the operation.
101
+ */
102
+ delete: _deleteToken,
103
+ /**
104
+ * Verifies an API token and retrieves associated user information.
105
+ *
106
+ * @param key - The API token to verify.
107
+ * @returns An Effect that resolves to user information if the token is valid, or false if invalid.
108
+ */
109
+ verify: _verifyToken
110
+ };
111
+ return { tokens };
112
+ });
113
+ var rest_api_default = SDKRestAPIModule;
114
+ export {
115
+ SDKRestAPIModule,
116
+ rest_api_default as default
117
+ };
@@ -0,0 +1,184 @@
1
+ import { Effect } from '@withstudiocms/effect';
2
+ import CacheService from '../../cache.js';
3
+ import { DBClientLive } from '../../context.js';
4
+ import { StudioCMSPageContent, StudioCMSPageData } from '../../tables.js';
5
+ /**
6
+ * CombinedPageUpdateData
7
+ *
8
+ * Type representing the combined data required to update both page data and page content.
9
+ */
10
+ type CombinedPageUpdateData = {
11
+ pageData: (typeof StudioCMSPageData.Update)['Type'];
12
+ pageContent: (typeof StudioCMSPageContent.Update)['Type'];
13
+ };
14
+ /**
15
+ * SDKUpdateModule
16
+ *
17
+ * Effect generator that constructs and returns the SDK "UPDATE" module containing all update-related operations
18
+ * for the StudioCMS domain. Each operation is implemented as an Effect and typically combines:
19
+ * - a DB update operation (wrapped with a codec for runtime encode/decode/validation),
20
+ * - optional cache invalidation or cache refresh,
21
+ * - and retrieval of the fresh resource via the GET module when appropriate.
22
+ *
23
+ * @module SDKUpdateModule
24
+ *
25
+ * @remarks
26
+ * - Dependencies resolved by the generator: DBClientLive, CacheService, SDKClearModule, SDKGetModule, SDKConfigModule.
27
+ * - DB operations are created via withCodec with corresponding encoder/decoder codecs (e.g. StudioCMSPageContent, StudioCMSPageData, StudioCMSPermissions, etc.).
28
+ * - Cache-related operations include clearing/invalidation of folder tree/list caches, page-specific cache deletion, and npm package cache tag invalidation.
29
+ * - Composite helpers coordinate multi-step flows, e.g. updating page content + page data + deleting the page cache, then returning the fresh page via GET.
30
+ * - All operations are effectful and intended to be executed inside the Effect runtime; callers should compose and run them using the Effect primitives provided by the environment.
31
+ *
32
+ * @returns {{
33
+ * pageContent: Effect, tags: Effect, categories: Effect, permissions: Effect,
34
+ * folderTree: Effect, folderList: Effect, folder: Effect,
35
+ * latestVersion: Effect, siteConfig: Effect,
36
+ * page: { byId: Effect, bySlug: Effect }
37
+ * }}
38
+ * An object exposing update operations:
39
+ * - pageContent, tags, categories, permissions: DB update Effects returning the updated record.
40
+ * - folderTree, folderList: Effects that refresh corresponding caches.
41
+ * - folder: updates a folder entry and invalidates/refreshes folder caches.
42
+ * - latestVersion: invalidates npm package cache tags and fetches the latest package version.
43
+ * - siteConfig: forwards to CONFIG.siteConfig.update.
44
+ * - page.byId: updates page data and content, deletes the page cache, refreshes folder caches, then returns the updated page.
45
+ * - page.bySlug: resolves the page id by slug and delegates to page.byId.
46
+ *
47
+ * @example
48
+ * // Typical usage inside an Effect:
49
+ * // yield* Effect.flatMap(UPDATE.page.byId('pageId', combinedPageUpdateData))
50
+ *
51
+ * @threadSafety
52
+ * Effects encapsulate async side effects; callers should treat composite updates as atomic logical operations but not assume cross-operation DB transactions unless provided by the DB client.
53
+ *
54
+ * @errors
55
+ * - DB client errors (e.g. executeTakeFirstOrThrow) propagate as Effect failures.
56
+ * - Codec validation errors are raised if supplied data does not conform to the expected codec schemas.
57
+ *
58
+ * @see SDKGetModule for read operations
59
+ * @see SDKClearModule for explicit cache clearing operations
60
+ */
61
+ export declare const SDKUpdateModule: Effect.Effect<{
62
+ /**
63
+ * Update Page Content
64
+ *
65
+ * @param data - The page content data to update.
66
+ * @returns The updated page content.
67
+ */
68
+ pageContent: (input: {
69
+ readonly id: string;
70
+ readonly contentLang: string;
71
+ readonly contentId: string;
72
+ readonly content: string;
73
+ }) => Effect.Effect<{
74
+ readonly id: string;
75
+ readonly contentLang: string;
76
+ readonly contentId: string;
77
+ readonly content: string;
78
+ }, import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
79
+ /**
80
+ * Update Tag
81
+ *
82
+ * @param data - The tag data to update.
83
+ * @returns The updated tag.
84
+ */
85
+ tags: (input: {
86
+ readonly id: number;
87
+ readonly name: string;
88
+ readonly description: string;
89
+ readonly slug: string;
90
+ readonly meta: string;
91
+ }) => Effect.Effect<{
92
+ readonly id: number;
93
+ readonly name: string;
94
+ readonly description: string;
95
+ readonly slug: string;
96
+ readonly meta: {
97
+ readonly [x: string]: unknown;
98
+ };
99
+ }, import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
100
+ /**
101
+ * Update Category
102
+ *
103
+ * @param data - The category data to update.
104
+ * @returns The updated category.
105
+ */
106
+ categories: (input: {
107
+ readonly id: number;
108
+ readonly name: string;
109
+ readonly description: string;
110
+ readonly parent?: number | null | undefined;
111
+ readonly slug: string;
112
+ readonly meta: string;
113
+ }) => Effect.Effect<{
114
+ readonly id: number;
115
+ readonly name: string;
116
+ readonly description: string;
117
+ readonly parent?: number | null | undefined;
118
+ readonly slug: string;
119
+ readonly meta: {
120
+ readonly [x: string]: unknown;
121
+ };
122
+ }, import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
123
+ /**
124
+ * Update Permissions
125
+ *
126
+ * @param data - The permissions data to update.
127
+ * @returns The updated permissions.
128
+ */
129
+ permissions: (input: {
130
+ readonly user: string;
131
+ readonly rank: "owner" | "admin" | "editor" | "visitor" | "unknown";
132
+ }) => Effect.Effect<{
133
+ readonly user: string;
134
+ readonly rank: "owner" | "admin" | "editor" | "visitor" | "unknown";
135
+ }, import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
136
+ /**
137
+ * Update Folder Tree Cache
138
+ */
139
+ folderTree: Effect.Effect<import("../../types.js").FolderNode[], import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError | import("../util/folderTree.js").FolderTreeError, never>;
140
+ /**
141
+ * Update Folder List Cache
142
+ */
143
+ folderList: Effect.Effect<import("../../types.js").FolderListItem[], import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
144
+ /**
145
+ * Update Folder Entry and Invalidate Related Caches
146
+ *
147
+ * @param data - The folder entry data to update.
148
+ * @returns The updated folder entry.
149
+ */
150
+ folder: (data: {
151
+ readonly id: string;
152
+ readonly name: string;
153
+ readonly parent?: string | null | undefined;
154
+ }) => Effect.Effect<{
155
+ readonly id: string;
156
+ readonly name: string;
157
+ readonly parent?: string | null | undefined;
158
+ }, import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError | import("../util/folderTree.js").FolderTreeError, never>;
159
+ /**
160
+ * Update Latest NPM Package Version
161
+ */
162
+ latestVersion: () => Effect.Effect<{
163
+ version: string;
164
+ lastCacheUpdate: Date;
165
+ }, import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError | import("../util/getFromNPM.js").GetFromNPMError, never>;
166
+ /**
167
+ * Update Site Configuration
168
+ */
169
+ siteConfig: (data: import("../../types.js").ConfigFinal<import("../../types.js").StudioCMSSiteConfig>) => Effect.Effect<import("../../types.js").DynamicConfigEntry<import("../../types.js").StudioCMSSiteConfig>, import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
170
+ /**
171
+ * Page Operations
172
+ */
173
+ page: {
174
+ /**
175
+ * Update Page by ID
176
+ */
177
+ byId: (pageId: string, data: CombinedPageUpdateData) => Effect.Effect<import("../../types.js").CombinedPageData | undefined, import("effect/ParseResult").ParseError | import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").QueryParseError | import("@withstudiocms/kysely/core/errors").QueryError | import("@withstudiocms/kysely/core/errors").NotFoundError | import("../util/folderTree.js").FolderTreeError | import("../util/collectors.js").CollectorError | import("../get/index.js").PaginateError, never>;
178
+ /**
179
+ * Update Page by Slug
180
+ */
181
+ bySlug: (slug: string, data: CombinedPageUpdateData) => Effect.Effect<import("../../types.js").CombinedPageData | undefined, import("effect/ParseResult").ParseError | import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError | import("../util/folderTree.js").FolderTreeError | import("../util/collectors.js").CollectorError | import("../get/index.js").PaginateError, never>;
182
+ };
183
+ }, never, DBClientLive | import("../../context.js").SDKDefaults | import("../../context.js").StorageManagerResolver | CacheService | import("@withstudiocms/effect").Deepmerge>;
184
+ export default SDKUpdateModule;
@@ -0,0 +1,192 @@
1
+ import { Effect, Schema } from "@withstudiocms/effect";
2
+ import CacheService from "../../cache.js";
3
+ import { cacheKeyGetters, cacheTags } from "../../consts.js";
4
+ import { DBClientLive } from "../../context.js";
5
+ import {
6
+ StudioCMSPageContent,
7
+ StudioCMSPageData,
8
+ StudioCMSPageDataCategories,
9
+ StudioCMSPageDataTags,
10
+ StudioCMSPageFolderStructure,
11
+ StudioCMSPermissions
12
+ } from "../../tables.js";
13
+ import SDKClearModule from "../clear/index.js";
14
+ import SDKConfigModule from "../config/index.js";
15
+ import SDKGetModule from "../get/index.js";
16
+ const SDKUpdateModule = Effect.gen(function* () {
17
+ const [{ withCodec }, CACHE, CLEAR, GET, CONFIG] = yield* Effect.all([
18
+ DBClientLive,
19
+ CacheService,
20
+ SDKClearModule,
21
+ SDKGetModule,
22
+ SDKConfigModule
23
+ ]);
24
+ const _updatePageContent = withCodec({
25
+ encoder: StudioCMSPageContent.Update,
26
+ decoder: StudioCMSPageContent.Select,
27
+ callbackFn: (db, data) => db(
28
+ (client) => client.transaction().execute(async (trx) => {
29
+ await trx.updateTable("StudioCMSPageContent").set(data).where("id", "=", data.id).executeTakeFirstOrThrow();
30
+ return await trx.selectFrom("StudioCMSPageContent").selectAll().where("id", "=", data.id).executeTakeFirstOrThrow();
31
+ })
32
+ )
33
+ });
34
+ const _updateTag = withCodec({
35
+ encoder: StudioCMSPageDataTags.Update,
36
+ decoder: StudioCMSPageDataTags.Select,
37
+ callbackFn: (db, data) => db(
38
+ (client) => client.transaction().execute(async (trx) => {
39
+ await trx.updateTable("StudioCMSPageDataTags").set(data).where("id", "=", data.id).executeTakeFirstOrThrow();
40
+ return await trx.selectFrom("StudioCMSPageDataTags").selectAll().where("id", "=", data.id).executeTakeFirstOrThrow();
41
+ })
42
+ )
43
+ });
44
+ const _updateCategory = withCodec({
45
+ encoder: StudioCMSPageDataCategories.Update,
46
+ decoder: StudioCMSPageDataCategories.Select,
47
+ callbackFn: (db, data) => db(
48
+ (client) => client.transaction().execute(async (trx) => {
49
+ await trx.updateTable("StudioCMSPageDataCategories").set(data).where("id", "=", data.id).executeTakeFirstOrThrow();
50
+ return await trx.selectFrom("StudioCMSPageDataCategories").selectAll().where("id", "=", data.id).executeTakeFirstOrThrow();
51
+ })
52
+ )
53
+ });
54
+ const _updatePermission = withCodec({
55
+ encoder: StudioCMSPermissions.Update,
56
+ decoder: StudioCMSPermissions.Select,
57
+ callbackFn: (db, data) => db(
58
+ (client) => client.transaction().execute(async (trx) => {
59
+ await trx.updateTable("StudioCMSPermissions").set(data).where("user", "=", data.user).executeTakeFirstOrThrow();
60
+ return await trx.selectFrom("StudioCMSPermissions").selectAll().where("user", "=", data.user).executeTakeFirstOrThrow();
61
+ })
62
+ )
63
+ });
64
+ const _updateFolderEntry = withCodec({
65
+ encoder: StudioCMSPageFolderStructure.Update,
66
+ decoder: StudioCMSPageFolderStructure.Select,
67
+ callbackFn: (db, data) => db(
68
+ (client) => client.transaction().execute(async (trx) => {
69
+ await trx.updateTable("StudioCMSPageFolderStructure").set(data).where("id", "=", data.id).executeTakeFirstOrThrow();
70
+ return await trx.selectFrom("StudioCMSPageFolderStructure").selectAll().where("id", "=", data.id).executeTakeFirstOrThrow();
71
+ })
72
+ )
73
+ });
74
+ const _updatePageDataEntry = withCodec({
75
+ encoder: StudioCMSPageData.Update,
76
+ decoder: StudioCMSPageData.Select,
77
+ callbackFn: (db, data) => db(
78
+ (client) => client.transaction().execute(async (trx) => {
79
+ await trx.updateTable("StudioCMSPageData").set(data).where("id", "=", data.id).executeTakeFirstOrThrow();
80
+ return await trx.selectFrom("StudioCMSPageData").selectAll().where("id", "=", data.id).executeTakeFirstOrThrow();
81
+ })
82
+ )
83
+ });
84
+ const _findPageDataBySlug = withCodec({
85
+ encoder: Schema.String,
86
+ decoder: StudioCMSPageData.Select,
87
+ callbackFn: (db, slug) => db(
88
+ (client) => client.selectFrom("StudioCMSPageData").where("slug", "=", slug).selectAll().executeTakeFirstOrThrow()
89
+ )
90
+ });
91
+ const _updateFolderTree = CLEAR.folderTree.pipe(Effect.flatMap(GET.folderTree));
92
+ const _updateFolderList = CLEAR.folderList.pipe(Effect.flatMap(GET.folderList));
93
+ const _updateFolderEntryAndInvalidate = Effect.fn(
94
+ (data) => _updateFolderEntry(data).pipe(
95
+ Effect.flatMap((src) => _updateFolderTree.pipe(Effect.as(src))),
96
+ Effect.flatMap((src) => _updateFolderList.pipe(Effect.as(src)))
97
+ )
98
+ );
99
+ const _updateLatestVersion = Effect.fn(
100
+ () => CACHE.invalidateTags(cacheTags.npmPackage).pipe(Effect.flatMap(GET.latestVersion))
101
+ );
102
+ const _updateFolderTreeAndList = Effect.all([_updateFolderTree, _updateFolderList]);
103
+ const _updatePageById = Effect.fn(
104
+ (pageId, data) => Effect.all([
105
+ _updatePageDataEntry(data.pageData),
106
+ _updatePageContent(data.pageContent),
107
+ CACHE.delete(cacheKeyGetters.page(pageId))
108
+ ]).pipe(
109
+ Effect.tap(() => _updateFolderTreeAndList),
110
+ Effect.flatMap(() => GET.page.byId(pageId))
111
+ )
112
+ );
113
+ const _findPageIdBySlug = Effect.fn(
114
+ (slug) => _findPageDataBySlug(slug).pipe(Effect.map(({ id }) => id))
115
+ );
116
+ const _updatePageByIdPiped = (data) => Effect.fn((id) => _updatePageById(id, data));
117
+ const _updatePageBySlug = Effect.fn(
118
+ (slug, data) => _findPageIdBySlug(slug).pipe(Effect.flatMap(_updatePageByIdPiped(data)))
119
+ );
120
+ const UPDATE = {
121
+ /**
122
+ * Update Page Content
123
+ *
124
+ * @param data - The page content data to update.
125
+ * @returns The updated page content.
126
+ */
127
+ pageContent: _updatePageContent,
128
+ /**
129
+ * Update Tag
130
+ *
131
+ * @param data - The tag data to update.
132
+ * @returns The updated tag.
133
+ */
134
+ tags: _updateTag,
135
+ /**
136
+ * Update Category
137
+ *
138
+ * @param data - The category data to update.
139
+ * @returns The updated category.
140
+ */
141
+ categories: _updateCategory,
142
+ /**
143
+ * Update Permissions
144
+ *
145
+ * @param data - The permissions data to update.
146
+ * @returns The updated permissions.
147
+ */
148
+ permissions: _updatePermission,
149
+ /**
150
+ * Update Folder Tree Cache
151
+ */
152
+ folderTree: _updateFolderTree,
153
+ /**
154
+ * Update Folder List Cache
155
+ */
156
+ folderList: _updateFolderList,
157
+ /**
158
+ * Update Folder Entry and Invalidate Related Caches
159
+ *
160
+ * @param data - The folder entry data to update.
161
+ * @returns The updated folder entry.
162
+ */
163
+ folder: _updateFolderEntryAndInvalidate,
164
+ /**
165
+ * Update Latest NPM Package Version
166
+ */
167
+ latestVersion: _updateLatestVersion,
168
+ /**
169
+ * Update Site Configuration
170
+ */
171
+ siteConfig: CONFIG.siteConfig.update,
172
+ /**
173
+ * Page Operations
174
+ */
175
+ page: {
176
+ /**
177
+ * Update Page by ID
178
+ */
179
+ byId: _updatePageById,
180
+ /**
181
+ * Update Page by Slug
182
+ */
183
+ bySlug: _updatePageBySlug
184
+ }
185
+ };
186
+ return UPDATE;
187
+ });
188
+ var update_default = SDKUpdateModule;
189
+ export {
190
+ SDKUpdateModule,
191
+ update_default as default
192
+ };
@@ -0,0 +1,125 @@
1
+ import { Effect, type ParseResult } from '@withstudiocms/effect';
2
+ import type { DBCallbackFailure } from '@withstudiocms/kysely/client';
3
+ import type { DatabaseError } from '@withstudiocms/kysely/core/errors';
4
+ import { DBClientLive, StorageManagerResolver } from '../../context.js';
5
+ import type { CombinedPageData, CombinedUserData, FolderNode, MetaOnlyPageData, tsPageDataSelect } from '../../types.js';
6
+ import { type FolderTreeError } from './folderTree.js';
7
+ declare const CollectorError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
8
+ readonly _tag: "CollectorError";
9
+ } & Readonly<A>;
10
+ /**
11
+ * Error class for collector errors.
12
+ */
13
+ export declare class CollectorError extends CollectorError_base<{
14
+ cause: unknown;
15
+ }> {
16
+ }
17
+ /**
18
+ * Utility function to handle errors in collector functions.
19
+ *
20
+ * @param _try - The function to execute that may throw an error.
21
+ * @returns An effect that either yields the result of the function or a CollectorError.
22
+ */
23
+ export declare const useCollectorError: <T>(_try: () => T) => Effect.Effect<T, CollectorError, never>;
24
+ /**
25
+ * SDKCollectors
26
+ *
27
+ * Effect generator that wires together database access, folder-tree utilities, and parsing helpers
28
+ * to produce a set of high-level "collector" utilities for assembling richer SDK models from
29
+ * raw database rows.
30
+ *
31
+ * Behavior
32
+ * - Instantiates required dependencies (DB client, folder-tree helpers, parsers) by yielding the
33
+ * corresponding live implementations.
34
+ * - Exposes a small collection of helper effects and functions that perform typed queries,
35
+ * transform results, and compose several queries into complete domain objects.
36
+ *
37
+ * Internal helpers (provided inside the effect)
38
+ * - _getUserData(id: string): Effect that queries StudioCMSUsersTable and decodes the result.
39
+ * - _getPageContent(id: string): Effect that queries StudioCMSPageContent for multi-language page
40
+ * content and decodes the result.
41
+ * - _getOAuthAccountData(id: string): Effect that queries StudioCMSOAuthAccounts for a user's
42
+ * OAuth accounts and decodes the result.
43
+ * - _getUserPermissionsData(id: string): Effect that queries StudioCMSPermissions for a user's
44
+ * permissions and decodes the result.
45
+ *
46
+ * Utility functions
47
+ * - _transformPageDataToMetaOnly:
48
+ * Transforms a CombinedPageData (or array thereof) into its metadata-only representation by
49
+ * stripping large content fields (defaultContent, multiLangContent). Returns an Effect that
50
+ * fails with a CollectorError when transformation fails.
51
+ * - _collectContributorData(ids: readonly string[]):
52
+ * Concurrently fetches user records for a list of contributor IDs and filters out missing
53
+ * results.
54
+ *
55
+ * Main collectors (returned object)
56
+ * - collectCategories(ids: number[]):
57
+ * Uses a codec-backed query to fetch category rows by id.
58
+ * - collectTags(ids: number[]):
59
+ * Uses a codec-backed query to fetch tag rows by id.
60
+ * - collectPageData(page, tree, metaOnly = false):
61
+ * Assembles a complete page model by concurrently collecting:
62
+ * - categories and tags (via parsers -> collectCategories/collectTags),
63
+ * - contributor user data,
64
+ * - author user data,
65
+ * - multi-language page content (when metaOnly is false).
66
+ * It computes a safe slug (special-casing "index" -> "/") and resolves the full URL
67
+ * route by walking the provided folder tree (using findNodesAlongPathToId) when a
68
+ * parentFolder is present.
69
+ * Overloads:
70
+ * - Without metaOnly (or metaOnly === false) returns CombinedPageData.
71
+ * - With metaOnly === true returns MetaOnlyPageData (content stripped via
72
+ * _transformPageDataToMetaOnly).
73
+ * Possible failure modes include DatabaseError, ParseResult.ParseError, FolderTreeError,
74
+ * and CollectorError.
75
+ * - collectUserData(user):
76
+ * Enriches a user row with its OAuth accounts and permissions and returns a CombinedUserData
77
+ * result.
78
+ *
79
+ * Errors
80
+ * - All operations are represented as Effects and may fail with the module's domain errors such
81
+ * as DatabaseError, ParseResult.ParseError, FolderTreeError, and CollectorError.
82
+ *
83
+ * Usage
84
+ * - The effect yields an object with the above collector functions which can be used by other
85
+ * SDK modules to obtain normalized, assembled data for pages, users, tags, and categories.
86
+ */
87
+ export declare const SDKCollectors: Effect.Effect<{
88
+ collectCategories: (input: readonly number[]) => Effect.Effect<readonly {
89
+ readonly id: number;
90
+ readonly name: string;
91
+ readonly description: string;
92
+ readonly parent?: number | null | undefined;
93
+ readonly slug: string;
94
+ readonly meta: {
95
+ readonly [x: string]: unknown;
96
+ };
97
+ }[], DBCallbackFailure | DatabaseError, never>;
98
+ collectTags: (input: readonly number[]) => Effect.Effect<readonly {
99
+ readonly id: number;
100
+ readonly name: string;
101
+ readonly description: string;
102
+ readonly slug: string;
103
+ readonly meta: {
104
+ readonly [x: string]: unknown;
105
+ };
106
+ }[], DBCallbackFailure | DatabaseError, never>;
107
+ collectPageData: {
108
+ (page: tsPageDataSelect, tree: FolderNode[]): Effect.Effect<CombinedPageData, CollectorError | FolderTreeError | DBCallbackFailure | DatabaseError | ParseResult.ParseError, never>;
109
+ (page: tsPageDataSelect, tree: FolderNode[], metaOnly: boolean): Effect.Effect<MetaOnlyPageData, CollectorError | FolderTreeError | DBCallbackFailure | DatabaseError | ParseResult.ParseError, never>;
110
+ };
111
+ collectUserData: (user: {
112
+ readonly id: string;
113
+ readonly url?: string | null | undefined;
114
+ readonly name: string;
115
+ readonly email?: string | null | undefined;
116
+ readonly avatar?: string | null | undefined;
117
+ readonly username: string;
118
+ readonly password?: string | null | undefined;
119
+ readonly updatedAt: Date;
120
+ readonly createdAt: Date;
121
+ readonly emailVerified: boolean;
122
+ readonly notifications?: string | null | undefined;
123
+ }) => Effect.Effect<CombinedUserData, DBCallbackFailure | DatabaseError, never>;
124
+ }, never, DBClientLive | StorageManagerResolver>;
125
+ export {};