@withstudiocms/sdk 0.0.0-beta.0 → 0.1.0-beta.1

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 (71) 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 +28 -0
  6. package/dist/consts.js +26 -0
  7. package/dist/context.d.ts +188 -0
  8. package/dist/context.js +33 -0
  9. package/dist/index.d.ts +1136 -0
  10. package/dist/index.js +24 -0
  11. package/dist/lib/diff.d.ts +39 -0
  12. package/dist/lib/diff.js +29 -0
  13. package/dist/lib/logger.d.ts +31 -0
  14. package/dist/lib/logger.js +131 -0
  15. package/dist/lib/pluginUtils.d.ts +221 -0
  16. package/dist/lib/pluginUtils.js +80 -0
  17. package/dist/modules/auth/index.d.ts +463 -0
  18. package/dist/modules/auth/index.js +412 -0
  19. package/dist/modules/clear/index.d.ts +72 -0
  20. package/dist/modules/clear/index.js +52 -0
  21. package/dist/modules/config/consts.d.ts +32 -0
  22. package/dist/modules/config/consts.js +18 -0
  23. package/dist/modules/config/index.d.ts +100 -0
  24. package/dist/modules/config/index.js +205 -0
  25. package/dist/modules/config/templates/mailer.d.ts +36 -0
  26. package/dist/modules/config/templates/mailer.js +218 -0
  27. package/dist/modules/config/type-utils.d.ts +13 -0
  28. package/dist/modules/config/type-utils.js +11 -0
  29. package/dist/modules/delete/index.d.ts +140 -0
  30. package/dist/modules/delete/index.js +274 -0
  31. package/dist/modules/diffTracking/index.d.ts +188 -0
  32. package/dist/modules/diffTracking/index.js +276 -0
  33. package/dist/modules/get/index.d.ts +272 -0
  34. package/dist/modules/get/index.js +466 -0
  35. package/dist/modules/index.d.ts +1003 -0
  36. package/dist/modules/index.js +37 -0
  37. package/dist/modules/init/index.d.ts +60 -0
  38. package/dist/modules/init/index.js +38 -0
  39. package/dist/modules/middleware/index.d.ts +56 -0
  40. package/dist/modules/middleware/index.js +50 -0
  41. package/dist/modules/notificationSettings/index.d.ts +57 -0
  42. package/dist/modules/notificationSettings/index.js +39 -0
  43. package/dist/modules/plugins/index.d.ts +166 -0
  44. package/dist/modules/plugins/index.js +261 -0
  45. package/dist/modules/post/index.d.ts +305 -0
  46. package/dist/modules/post/index.js +305 -0
  47. package/dist/modules/resetTokenBucket/index.d.ts +91 -0
  48. package/dist/modules/resetTokenBucket/index.js +93 -0
  49. package/dist/modules/rest_api/index.d.ts +92 -0
  50. package/dist/modules/rest_api/index.js +113 -0
  51. package/dist/modules/update/index.d.ts +184 -0
  52. package/dist/modules/update/index.js +174 -0
  53. package/dist/modules/util/collectors.d.ts +261 -0
  54. package/dist/modules/util/collectors.js +141 -0
  55. package/dist/modules/util/folderTree.d.ts +100 -0
  56. package/dist/modules/util/folderTree.js +176 -0
  57. package/dist/modules/util/generators.d.ts +83 -0
  58. package/dist/modules/util/generators.js +106 -0
  59. package/dist/modules/util/getFromNPM.d.ts +191 -0
  60. package/dist/modules/util/getFromNPM.js +100 -0
  61. package/dist/modules/util/index.d.ts +236 -0
  62. package/dist/modules/util/index.js +20 -0
  63. package/dist/modules/util/parsers.d.ts +60 -0
  64. package/dist/modules/util/parsers.js +43 -0
  65. package/dist/modules/util/slugify.d.ts +22 -0
  66. package/dist/modules/util/slugify.js +19 -0
  67. package/dist/modules/util/users.d.ts +99 -0
  68. package/dist/modules/util/users.js +78 -0
  69. package/dist/types.d.ts +360 -0
  70. package/dist/types.js +10 -0
  71. package/package.json +55 -7
@@ -0,0 +1,305 @@
1
+ import { Effect, pipe, Schema } from "@withstudiocms/effect";
2
+ import {
3
+ DBCallbackFailure,
4
+ StudioCMSDiffTracking,
5
+ StudioCMSPageContent,
6
+ StudioCMSPageData,
7
+ StudioCMSPageDataCategories,
8
+ StudioCMSPageDataTags,
9
+ StudioCMSPageFolderStructure,
10
+ StudioCMSPermissions
11
+ } from "@withstudiocms/kysely";
12
+ import CacheService from "../../cache.js";
13
+ import { cacheTags } from "../../consts.js";
14
+ import { DBClientLive } from "../../context.js";
15
+ import SDKClearModule from "../clear/index.js";
16
+ import SDKGetModule from "../get/index.js";
17
+ import SDKUpdateModule from "../update/index.js";
18
+ import { SDKGenerators } from "../util/generators.js";
19
+ class PermissionExistsError {
20
+ _tag = "PermissionExistsError";
21
+ }
22
+ const SDKPostModule = Effect.gen(function* () {
23
+ const [{ withCodec }, clear, update, GET, { generateRandomIDNumber }, { invalidateTags }] = yield* Effect.all([
24
+ DBClientLive,
25
+ SDKClearModule,
26
+ SDKUpdateModule,
27
+ SDKGetModule,
28
+ SDKGenerators,
29
+ CacheService
30
+ ]);
31
+ const _insertPageData = withCodec({
32
+ encoder: StudioCMSPageData.Insert,
33
+ decoder: Schema.Struct({
34
+ id: Schema.String
35
+ }),
36
+ callbackFn: (db, data) => db(
37
+ (client) => client.insertInto("StudioCMSPageData").values(data).returning("id").executeTakeFirstOrThrow()
38
+ )
39
+ });
40
+ const _insertPageContent = withCodec({
41
+ encoder: StudioCMSPageContent.Insert,
42
+ decoder: Schema.Struct({
43
+ id: Schema.String
44
+ }),
45
+ callbackFn: (db, data) => db(
46
+ (client) => client.insertInto("StudioCMSPageContent").values(data).returning("id").executeTakeFirstOrThrow()
47
+ )
48
+ });
49
+ const _insertTagData = withCodec({
50
+ encoder: StudioCMSPageDataTags.Insert,
51
+ decoder: Schema.Struct({
52
+ id: Schema.Number
53
+ }),
54
+ callbackFn: (db, data) => db(
55
+ (client) => client.insertInto("StudioCMSPageDataTags").values(data).returning("id").executeTakeFirstOrThrow()
56
+ )
57
+ });
58
+ const _insertCategoryData = withCodec({
59
+ encoder: StudioCMSPageDataCategories.Insert,
60
+ decoder: Schema.Struct({
61
+ id: Schema.Number
62
+ }),
63
+ callbackFn: (db, data) => db(
64
+ (client) => client.insertInto("StudioCMSPageDataCategories").values(data).returning("id").executeTakeFirstOrThrow()
65
+ )
66
+ });
67
+ const _getUserPermission = withCodec({
68
+ encoder: Schema.String,
69
+ decoder: StudioCMSPermissions.Select,
70
+ callbackFn: (db, userId) => db(
71
+ (client) => client.selectFrom("StudioCMSPermissions").selectAll().where("user", "=", userId).executeTakeFirstOrThrow()
72
+ )
73
+ });
74
+ const _insertNewUserPermission = withCodec({
75
+ encoder: StudioCMSPermissions.Insert,
76
+ decoder: StudioCMSPermissions.Select,
77
+ callbackFn: (db, data) => db(
78
+ (client) => client.insertInto("StudioCMSPermissions").values(data).returningAll().executeTakeFirstOrThrow()
79
+ )
80
+ });
81
+ const _insertNewDiffTracking = withCodec({
82
+ encoder: StudioCMSDiffTracking.Insert,
83
+ decoder: StudioCMSDiffTracking.Select,
84
+ callbackFn: (db, data) => db(
85
+ (client) => client.insertInto("StudioCMSDiffTracking").values(data).returningAll().executeTakeFirstOrThrow()
86
+ )
87
+ });
88
+ const _insertNewFolder = withCodec({
89
+ encoder: StudioCMSPageFolderStructure.Insert,
90
+ decoder: StudioCMSPageFolderStructure.Select,
91
+ callbackFn: (db, data) => db(
92
+ (client) => client.insertInto("StudioCMSPageFolderStructure").values(data).returningAll().executeTakeFirstOrThrow()
93
+ )
94
+ });
95
+ const _randomUUIDString = Effect.fn(() => Effect.succeed(crypto.randomUUID().toString()));
96
+ const _pageDataIdOrGenerateUUID = Effect.fn(function* (data) {
97
+ const id = data.id || (yield* _randomUUIDString());
98
+ return { id, ...data };
99
+ });
100
+ const _insertNewPageWithContent = Effect.fn(
101
+ (pageData, pageContent) => Effect.all({
102
+ pageData: _pageDataIdOrGenerateUUID(pageData),
103
+ pageContent: Effect.succeed(pageContent)
104
+ }).pipe(
105
+ Effect.flatMap(
106
+ ({ pageData: { id, contentLang, ...basePageData }, pageContent: pageContent2 }) => Effect.all({
107
+ pageData: _insertPageData({
108
+ ...basePageData,
109
+ id,
110
+ contentLang
111
+ }),
112
+ pageContent: _insertPageContent({
113
+ id: crypto.randomUUID().toString(),
114
+ contentId: id,
115
+ contentLang,
116
+ content: pageContent2.content || ""
117
+ })
118
+ })
119
+ ),
120
+ Effect.tap(() => invalidateTags(cacheTags.pages))
121
+ )
122
+ );
123
+ const _insertPageWithContentArray = Effect.fn(
124
+ (pages) => Effect.all(
125
+ pages.map(({ pageData, pageContent }) => _insertNewPageWithContent(pageData, pageContent))
126
+ )
127
+ );
128
+ const _pickIdOrGenerate = Effect.fn(function* (data) {
129
+ const id = data.id || (yield* generateRandomIDNumber(9));
130
+ return { id, ...data };
131
+ });
132
+ const _insertNewTag = Effect.fn(
133
+ (tag) => _pickIdOrGenerate(tag).pipe(Effect.flatMap(_insertTagData))
134
+ );
135
+ const _insertTagArray = Effect.fn(
136
+ (tags) => Effect.all(tags.map((tag) => _insertNewTag(tag)))
137
+ );
138
+ const _insertNewCategory = Effect.fn(
139
+ (category) => _pickIdOrGenerate(category).pipe(Effect.flatMap(_insertCategoryData))
140
+ );
141
+ const _insertCategoryArray = Effect.fn(
142
+ (categories) => Effect.all(categories.map((category) => _insertNewCategory(category)))
143
+ );
144
+ const _insertNewPermission = Effect.fn(
145
+ (userId, rank) => _getUserPermission(userId).pipe(
146
+ Effect.flatMap(
147
+ (exists) => exists ? Effect.fail(new PermissionExistsError()) : Effect.succeed({ user: userId, rank })
148
+ ),
149
+ Effect.flatMap((data) => _insertNewUserPermission(data)),
150
+ Effect.catchTag(
151
+ "PermissionExistsError",
152
+ () => Effect.fail(
153
+ new DBCallbackFailure({
154
+ cause: "Permission for user already exists, Please update instead."
155
+ })
156
+ )
157
+ )
158
+ )
159
+ );
160
+ const _insertPermissionArray = Effect.fn(
161
+ (permissions) => Effect.all(permissions.map(({ userId, rank }) => _insertNewPermission(userId, rank)))
162
+ );
163
+ const _insertDiffTracking = Effect.fn(
164
+ (data) => pipe(
165
+ data.id ? Effect.succeed(data) : _randomUUIDString().pipe(Effect.map((id) => ({ id, ...data }))),
166
+ Effect.flatMap((dataWithId) => _insertNewDiffTracking(dataWithId))
167
+ )
168
+ );
169
+ const _insertFolder = Effect.fn(
170
+ (data) => pipe(
171
+ data.id ? Effect.succeed(data) : _randomUUIDString().pipe(Effect.map((id) => ({ id, ...data }))),
172
+ Effect.flatMap((dataWithId) => _insertNewFolder(dataWithId))
173
+ )
174
+ );
175
+ const _mainInsertFolder = Effect.fn(
176
+ (data) => _insertFolder(data).pipe(Effect.tap(() => Effect.all([update.folderList, update.folderTree])))
177
+ );
178
+ const _mainInsertPage = Effect.fn(
179
+ ({
180
+ pageData,
181
+ pageContent
182
+ }) => _insertNewPageWithContent(pageData, pageContent).pipe(
183
+ Effect.flatMap(({ pageData: { id } }) => GET.page.byId(id)),
184
+ Effect.tap(
185
+ () => Effect.all([
186
+ clear.folderList,
187
+ clear.folderTree,
188
+ invalidateTags([
189
+ ...cacheTags.pages,
190
+ ...cacheTags.pageFolderTree,
191
+ ...cacheTags.folderTree
192
+ ])
193
+ ])
194
+ )
195
+ )
196
+ );
197
+ const databaseEntry = {
198
+ /**
199
+ * Inserts a new page along with its content into the database.
200
+ *
201
+ * @param pageData - The data for the new page, excluding the ID.
202
+ * @param pageContent - The content for the new page.
203
+ * @returns An effect that resolves to an object containing the IDs of the newly inserted page data and content.
204
+ */
205
+ pages: _insertNewPageWithContent,
206
+ /**
207
+ * Inserts a new page content entry into the database.
208
+ *
209
+ * @param data - The page content data to be inserted.
210
+ * @returns An effect that resolves to the ID of the newly inserted page content.
211
+ */
212
+ pageContent: _insertPageContent,
213
+ /**
214
+ * Inserts a new page data tag into the database.
215
+ *
216
+ * @param tag - The tag data to be inserted.
217
+ * @returns An effect that resolves to the ID of the newly inserted tag.
218
+ */
219
+ tags: _insertNewTag,
220
+ /**
221
+ * Inserts a new page data category into the database.
222
+ *
223
+ * @param category - The category data to be inserted.
224
+ * @returns An effect that resolves to the ID of the newly inserted category.
225
+ */
226
+ categories: _insertNewCategory,
227
+ /**
228
+ * Inserts a new permission entry for a user into the database.
229
+ *
230
+ * @param userId - The ID of the user for whom the permission is to be created.
231
+ * @param rank - The rank of the permission to be assigned.
232
+ * @returns An effect that resolves to the newly inserted permission entry.
233
+ */
234
+ permissions: _insertNewPermission,
235
+ /**
236
+ * Inserts a new diff tracking entry into the database.
237
+ *
238
+ * @param data - The diff tracking data to be inserted.
239
+ * @returns An effect that resolves to the newly inserted diff tracking entry.
240
+ */
241
+ diffTracking: _insertDiffTracking,
242
+ /**
243
+ * Inserts a new folder structure entry into the database.
244
+ *
245
+ * @param data - The folder structure data to be inserted.
246
+ * @returns An effect that resolves to the newly inserted folder structure entry.
247
+ */
248
+ folder: _insertFolder
249
+ };
250
+ const databaseEntries = {
251
+ /**
252
+ * Inserts an array of new page data tags into the database.
253
+ *
254
+ * @param tags - The array of tag data to be inserted.
255
+ * @returns An effect that resolves to an array of IDs of the newly inserted tags.
256
+ */
257
+ tags: _insertTagArray,
258
+ /**
259
+ * Inserts an array of new page data categories into the database.
260
+ *
261
+ * @param categories - The array of category data to be inserted.
262
+ * @returns An effect that resolves to an array of IDs of the newly inserted categories.
263
+ */
264
+ categories: _insertCategoryArray,
265
+ /**
266
+ * Inserts an array of new permissions into the database.
267
+ *
268
+ * @param permissions - The array of permission data to be inserted.
269
+ * @returns An effect that resolves to an array of newly inserted permission entries.
270
+ */
271
+ permissions: _insertPermissionArray,
272
+ /**
273
+ * Inserts an array of new pages along with their content into the database.
274
+ *
275
+ * @param data - An array of PageInsert objects containing page data and content.
276
+ * @returns An effect that resolves to an array of objects containing the IDs of the newly inserted page data and content for each page.
277
+ */
278
+ pages: _insertPageWithContentArray
279
+ };
280
+ return {
281
+ databaseEntry,
282
+ databaseEntries,
283
+ /**
284
+ * Inserts a new folder structure entry into the database, ensuring it has an ID.
285
+ *
286
+ * @param data - The folder structure data to be inserted.
287
+ * @returns An effect that resolves to the newly inserted folder structure entry.
288
+ */
289
+ folder: _mainInsertFolder,
290
+ /**
291
+ * Inserts a new page along with its content into the database.
292
+ *
293
+ * @param pageData - The data for the new page, excluding the ID.
294
+ * @param pageContent - The content for the new page.
295
+ * @returns An effect that resolves to the newly inserted page data.
296
+ */
297
+ page: _mainInsertPage
298
+ };
299
+ });
300
+ var post_default = SDKPostModule;
301
+ export {
302
+ PermissionExistsError,
303
+ SDKPostModule,
304
+ post_default as default
305
+ };
@@ -0,0 +1,91 @@
1
+ import { Effect } from '@withstudiocms/effect';
2
+ import { type DBCallbackFailure } from '@withstudiocms/kysely';
3
+ import type { DatabaseError } from '@withstudiocms/kysely/core/errors';
4
+ import { DBClientLive } from '../../context.js';
5
+ /**
6
+ * Error class representing a failure in the reset token bucket operations.
7
+ */
8
+ export declare class resetTokenBucketFail {
9
+ readonly _tag = "resetTokenBucketFail";
10
+ }
11
+ /**
12
+ * SDKResetTokenBucketModule
13
+ *
14
+ * Effectful module that provides reset-token management backed by the application database
15
+ * and a JWT-based token generator/verifier. The module is constructed as an Effect generator
16
+ * and depends on the DB client layer and token-generation/test utilities (resolved via
17
+ * DBClientLive and SDKGenerators).
18
+ *
19
+ * The resolved value is an object exposing three primary operations:
20
+ * - new(userId: string): Effect<E, Error, StudioCMSUserResetTokens.Select.Type>
21
+ * - Generates a cryptographically strong token for the supplied userId, persists a new
22
+ * reset-token record (with a generated UUID id and the token string) into the
23
+ * StudioCMSUserResetTokens table, and returns the inserted DB record.
24
+ * - Side effects: inserts into the DB, uses token-generation service.
25
+ * - Errors: database errors or generator errors may be raised by the returned effect.
26
+ *
27
+ * - delete(userId: string): Effect<E, Error, void>
28
+ * - Deletes any reset-token record(s) associated with the supplied userId.
29
+ * - Side effects: deletes from the DB.
30
+ * - Errors: database errors may be raised by the returned effect.
31
+ *
32
+ * - check(token: string): Effect<E, never, boolean>
33
+ * - Verifies whether the provided token is valid and matches the currently stored
34
+ * reset-token for the associated user:
35
+ * 1. Validates and verifies the token using the token verifier.
36
+ * 2. Retrieves the stored token record for the userId extracted from the token.
37
+ * 3. Compares the stored token string to the provided token and returns true/false.
38
+ * - The method treats invalid token verification as a domain failure type
39
+ * (resetTokenBucketFail) internally; that failure is caught and normalized to `false`.
40
+ * - Side effects: reads from the DB, uses token verification service.
41
+ * - Errors: unexpected runtime/database errors may still surface from the returned effect.
42
+ *
43
+ * Remarks:
44
+ * - The implementation uses codec- and encoder-wrappers for DB interactions (encoders/decoders
45
+ * for StudioCMSUserResetTokens) to ensure schema conformance on read/write.
46
+ * - Token creation uses a generated UUID for the DB record id and a generator service for the
47
+ * token payload. Token verification relies on the provided testToken function (from SDKGenerators).
48
+ * - The `check` operation intentionally swallows the domain-level `resetTokenBucketFail` and
49
+ * returns `false` to represent invalid/malformed tokens as a boolean outcome; other errors
50
+ * (e.g. DB connectivity) are not masked.
51
+ *
52
+ * Example:
53
+ * const resetBucket = yield* Effect.runPromise(SDKResetTokenBucketModule);
54
+ * await Effect.runPromise(resetBucket.new("user-id"));
55
+ * const isValid = await Effect.runPromise(resetBucket.check("token-string"));
56
+ *
57
+ * Type parameters and environment:
58
+ * - The module itself is returned as an Effect and therefore requires the Effect environment
59
+ * that provides the DB and token generator/test layers. Consumers should provide those
60
+ * dependencies when running the effect.
61
+ *
62
+ * @public
63
+ */
64
+ export declare const SDKResetTokenBucketModule: Effect.Effect<{
65
+ /**
66
+ * Creates a new reset token for the specified user.
67
+ *
68
+ * @param userId - The ID of the user for whom to create the reset token.
69
+ * @returns An effect yielding the created reset token record.
70
+ */
71
+ new: (userId: string) => Effect.Effect<{
72
+ readonly id: string;
73
+ readonly userId: string;
74
+ readonly token: string;
75
+ }, DBCallbackFailure | DatabaseError | import("../util/generators.js").GeneratorError, never>;
76
+ /**
77
+ * Deletes the reset token for the specified user.
78
+ *
79
+ * @param userId - The ID of the user for whom to delete the reset token.
80
+ * @returns An effect yielding the result of the delete operation.
81
+ */
82
+ delete: (input: string) => Effect.Effect<import("kysely").DeleteResult[], DBCallbackFailure | DatabaseError, never>;
83
+ /**
84
+ * Checks if the specified reset token is valid.
85
+ *
86
+ * @param token - The reset token to check.
87
+ * @returns An effect yielding a boolean indicating whether the token is valid.
88
+ */
89
+ check: (token: string) => Effect.Effect<boolean, DBCallbackFailure | DatabaseError | import("../util/generators.js").GeneratorError, never>;
90
+ }, import("effect/ConfigError").ConfigError, DBClientLive>;
91
+ export default SDKResetTokenBucketModule;
@@ -0,0 +1,93 @@
1
+ import { Effect, Schema } from "@withstudiocms/effect";
2
+ import { StudioCMSUserResetTokens } from "@withstudiocms/kysely";
3
+ import { DBClientLive } from "../../context.js";
4
+ import { SDKGenerators } from "../util/generators.js";
5
+ class resetTokenBucketFail {
6
+ _tag = "resetTokenBucketFail";
7
+ }
8
+ const SDKResetTokenBucketModule = Effect.gen(function* () {
9
+ const [{ withCodec, withEncoder }, { generateToken, testToken }] = yield* Effect.all([
10
+ DBClientLive,
11
+ SDKGenerators
12
+ ]);
13
+ const _createNewToken = withCodec({
14
+ encoder: StudioCMSUserResetTokens.Insert,
15
+ decoder: StudioCMSUserResetTokens.Select,
16
+ callbackFn: (db, data) => db(
17
+ (client) => client.insertInto("StudioCMSUserResetTokens").values(data).returningAll().executeTakeFirstOrThrow()
18
+ )
19
+ });
20
+ const _deleteTokenByUserId = withEncoder({
21
+ encoder: Schema.String,
22
+ callbackFn: (db, userId) => db(
23
+ (client) => client.deleteFrom("StudioCMSUserResetTokens").where("userId", "=", userId).execute()
24
+ )
25
+ });
26
+ const _getTokenByUserId = withCodec({
27
+ encoder: Schema.String,
28
+ decoder: Schema.UndefinedOr(StudioCMSUserResetTokens.Select),
29
+ callbackFn: (db, userId) => db(
30
+ (client) => client.selectFrom("StudioCMSUserResetTokens").selectAll().where("userId", "=", userId).executeTakeFirst()
31
+ )
32
+ });
33
+ const _createUserResetToken = Effect.fn(
34
+ (userId) => generateToken(userId).pipe(
35
+ Effect.flatMap(
36
+ (token) => _createNewToken({
37
+ id: crypto.randomUUID(),
38
+ userId,
39
+ token
40
+ })
41
+ )
42
+ )
43
+ );
44
+ const _checkIfValid = Effect.fn(
45
+ (token) => !token.isValid || !token.userId ? Effect.fail(new resetTokenBucketFail()) : Effect.succeed(token)
46
+ );
47
+ const _getTokenInfo = Effect.fn(
48
+ ({
49
+ userId
50
+ }) => userId ? _getTokenByUserId(userId) : Effect.fail(new resetTokenBucketFail())
51
+ );
52
+ const _verifyTokenMatch = (token) => Effect.fn(
53
+ (resetToken) => resetToken ? Effect.succeed(resetToken.token === token) : Effect.fail(new resetTokenBucketFail())
54
+ );
55
+ const _checkToken = Effect.fn(
56
+ (token) => testToken(token).pipe(
57
+ Effect.flatMap(_checkIfValid),
58
+ Effect.flatMap(_getTokenInfo),
59
+ Effect.flatMap(_verifyTokenMatch(token)),
60
+ Effect.catchTag("resetTokenBucketFail", () => Effect.succeed(false))
61
+ )
62
+ );
63
+ const resetTokenBucket = {
64
+ /**
65
+ * Creates a new reset token for the specified user.
66
+ *
67
+ * @param userId - The ID of the user for whom to create the reset token.
68
+ * @returns An effect yielding the created reset token record.
69
+ */
70
+ new: _createUserResetToken,
71
+ /**
72
+ * Deletes the reset token for the specified user.
73
+ *
74
+ * @param userId - The ID of the user for whom to delete the reset token.
75
+ * @returns An effect yielding the result of the delete operation.
76
+ */
77
+ delete: _deleteTokenByUserId,
78
+ /**
79
+ * Checks if the specified reset token is valid.
80
+ *
81
+ * @param token - The reset token to check.
82
+ * @returns An effect yielding a boolean indicating whether the token is valid.
83
+ */
84
+ check: _checkToken
85
+ };
86
+ return resetTokenBucket;
87
+ });
88
+ var resetTokenBucket_default = SDKResetTokenBucketModule;
89
+ export {
90
+ SDKResetTokenBucketModule,
91
+ resetTokenBucket_default as default,
92
+ resetTokenBucketFail
93
+ };
@@ -0,0 +1,92 @@
1
+ import { Effect } from '@withstudiocms/effect';
2
+ import { DBClientLive } from '../../context.js';
3
+ /**
4
+ * SDKRestAPIModule
5
+ *
6
+ * Effect-based module that provides REST API operations for managing StudioCMS API keys and verifying tokens.
7
+ *
8
+ * @remarks
9
+ * - Composed with DBClientLive and SDKGenerators (exposes withCodec, withEncoder and generateToken).
10
+ * - Persists and queries data against the 'StudioCMSAPIKeys' and 'StudioCMSPermissions' tables.
11
+ * - All public operations are provided as Effects and use runtime codecs/encoders for input/output validation.
12
+ * - New keys are generated via the provided generator and persisted with a UUID created by crypto.randomUUID().
13
+ *
14
+ * Exposed surface (tokens):
15
+ * - tokens.get(userId: string): Effect<StudioCMSAPIKeys.Select[]>
16
+ * Retrieves all API tokens for the specified user.
17
+ *
18
+ * - tokens.new(userId: string, description: string): Effect<StudioCMSAPIKeys.Select>
19
+ * Generates a new API key for the given user, persists it, and returns the created record.
20
+ *
21
+ * - tokens.delete({ userId: string; tokenId: string }): Effect<void>
22
+ * Deletes the specified API token for the user.
23
+ *
24
+ * - tokens.verify(key: string): Effect<{ userId: string; key: string; rank: number } | false>
25
+ * Validates the provided API key. If valid, returns the associated userId, key and permission rank; otherwise returns false.
26
+ *
27
+ * @returns An Effect that resolves to an object containing the `tokens` API.
28
+ *
29
+ * @example
30
+ * // Usage (conceptual)
31
+ * const { tokens } = yield* SDKRestAPIModule;
32
+ * const created = yield* tokens.new('user-123', 'automation key');
33
+ * const all = yield* tokens.get('user-123');
34
+ * const infoOrFalse = yield* tokens.verify(created.key);
35
+ */
36
+ export declare const SDKRestAPIModule: Effect.Effect<{
37
+ tokens: {
38
+ /**
39
+ * Retrieves all API tokens for a specific user.
40
+ *
41
+ * @param userId - The ID of the user whose tokens are to be retrieved.
42
+ * @returns An Effect that resolves to an array of API keys for the user.
43
+ * @throws {LibSQLDatabaseError} If a database error occurs during the operation.
44
+ */
45
+ get: (input: string) => Effect.Effect<readonly {
46
+ readonly key: string;
47
+ readonly id: string;
48
+ readonly description: string | null | undefined;
49
+ readonly userId: string;
50
+ readonly creationDate: Date;
51
+ }[], import("@withstudiocms/kysely").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
52
+ /**
53
+ * Creates a new API token for a user with the specified description.
54
+ *
55
+ * @param userId - The ID of the user for whom to create the token.
56
+ * @param description - A description for the API key.
57
+ * @returns An Effect that resolves to the created API key record.
58
+ * @throws {LibSQLDatabaseError} If a database error occurs during the operation.
59
+ */
60
+ new: (userId: string, description: string) => Effect.Effect<{
61
+ readonly key: string;
62
+ readonly id: string;
63
+ readonly description: string | null | undefined;
64
+ readonly userId: string;
65
+ readonly creationDate: Date;
66
+ }, import("@withstudiocms/kysely").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError | import("../util/generators.js").GeneratorError, never>;
67
+ /**
68
+ * Deletes an API token for a user by its ID.
69
+ *
70
+ * @param userId - The ID of the user whose token is to be deleted.
71
+ * @param tokenId - The ID of the API token to delete.
72
+ * @returns An Effect that resolves when the token is successfully deleted.
73
+ * @throws {LibSQLDatabaseError} If a database error occurs during the operation.
74
+ */
75
+ delete: (input: {
76
+ readonly userId: string;
77
+ readonly tokenId: string;
78
+ }) => Effect.Effect<import("kysely").DeleteResult[], import("@withstudiocms/kysely").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
79
+ /**
80
+ * Verifies an API token and retrieves associated user information.
81
+ *
82
+ * @param key - The API token to verify.
83
+ * @returns An Effect that resolves to user information if the token is valid, or false if invalid.
84
+ */
85
+ verify: (key: string) => Effect.Effect<false | {
86
+ userId: string;
87
+ key: string;
88
+ rank: "owner" | "admin" | "editor" | "visitor" | "unknown";
89
+ }, import("@withstudiocms/kysely").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, never>;
90
+ };
91
+ }, import("effect/ConfigError").ConfigError, DBClientLive>;
92
+ export default SDKRestAPIModule;