@studiocms/devapps 0.1.0-beta.9 → 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.
- package/LICENSE +1 -1
- package/README.md +3 -23
- package/dist/effects/WordPressAPI/configs.d.ts +87 -0
- package/dist/effects/WordPressAPI/configs.js +88 -0
- package/dist/effects/WordPressAPI/converters.d.ts +57 -0
- package/dist/effects/WordPressAPI/converters.js +331 -0
- package/dist/effects/WordPressAPI/errors.d.ts +12 -0
- package/dist/effects/WordPressAPI/errors.js +6 -0
- package/dist/effects/WordPressAPI/importers.d.ts +19 -0
- package/dist/effects/WordPressAPI/importers.js +122 -0
- package/dist/effects/WordPressAPI/schema.d.ts +478 -0
- package/dist/effects/WordPressAPI/schema.js +127 -0
- package/dist/effects/WordPressAPI/utils.d.ts +17 -0
- package/dist/effects/WordPressAPI/utils.js +239 -0
- package/dist/effects/wpImporter.d.ts +14 -0
- package/dist/effects/wpImporter.js +88 -0
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -16
- package/dist/routes/wp-importer.d.ts +0 -25
- package/dist/routes/wp-importer.js +9 -54
- package/dist/schema/index.d.ts +0 -24
- package/dist/schema/index.js +1 -13
- package/dist/utils/pathGenerator.js +3 -1
- package/dist/virt.d.ts +1 -5
- package/package.json +25 -31
- package/dist/apps/libsql-viewer.d.ts +0 -46
- package/dist/apps/libsql-viewer.js +0 -95
- package/dist/schema/wp-api.d.ts +0 -439
- package/dist/schema/wp-api.js +0 -72
- package/dist/utils/wp-api/converters.d.ts +0 -74
- package/dist/utils/wp-api/converters.js +0 -181
- package/dist/utils/wp-api/index.d.ts +0 -6
- package/dist/utils/wp-api/index.js +0 -3
- package/dist/utils/wp-api/pages.d.ts +0 -13
- package/dist/utils/wp-api/pages.js +0 -38
- package/dist/utils/wp-api/posts.d.ts +0 -10
- package/dist/utils/wp-api/posts.js +0 -38
- package/dist/utils/wp-api/settings.d.ts +0 -18
- package/dist/utils/wp-api/settings.js +0 -45
- package/dist/utils/wp-api/utils.d.ts +0 -66
- package/dist/utils/wp-api/utils.js +0 -138
- package/dist/virt.d.js +0 -0
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2025-present StudioCMS - withstudiocms (https://github.com/withstudiocms)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# StudioCMS - Development Apps
|
|
2
2
|
|
|
3
|
+
[](https://codecov.io/github/withstudiocms/studiocms)
|
|
4
|
+
|
|
3
5
|
Collection* of useful tools available during dev mode in Astro
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
@@ -50,28 +52,6 @@ export default defineConfig({
|
|
|
50
52
|
|
|
51
53
|
All tools will only be available during `astro dev` and will not be available during production deployments!
|
|
52
54
|
|
|
53
|
-
### libSQL Viewer
|
|
54
|
-
|
|
55
|
-
#### Requires
|
|
56
|
-
|
|
57
|
-
The following env variables set (`@astrojs/db`):
|
|
58
|
-
- **`ASTRO_DB_REMOTE_URL`**
|
|
59
|
-
- **`ASTRO_DB_APP_TOKEN`**
|
|
60
|
-
|
|
61
|
-
#### Preview
|
|
62
|
-
|
|
63
|
-
- Toolbar app
|
|
64
|
-
|
|
65
|
-

|
|
66
|
-
|
|
67
|
-
- Toolbar app Embedded
|
|
68
|
-
|
|
69
|
-

|
|
70
|
-
|
|
71
|
-
- Full page View
|
|
72
|
-
|
|
73
|
-

|
|
74
|
-
|
|
75
55
|
### WordPress Importer
|
|
76
56
|
|
|
77
57
|
#### Requires
|
|
@@ -88,5 +68,5 @@ The following env variables set (`@astrojs/db`):
|
|
|
88
68
|
|
|
89
69
|
## Licensing
|
|
90
70
|
|
|
91
|
-
[MIT Licensed](
|
|
71
|
+
[MIT Licensed](./LICENSE).
|
|
92
72
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { APIContext } from 'astro';
|
|
2
|
+
import { Context, Effect, Layer } from 'studiocms/effect';
|
|
3
|
+
import type { PageData } from './importers.js';
|
|
4
|
+
declare const StringConfig_base: Context.TagClass<StringConfig, "StringConfig", {
|
|
5
|
+
readonly str: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare class StringConfig extends StringConfig_base {
|
|
8
|
+
static makeLayer: (str: string) => Layer.Layer<StringConfig, never, never>;
|
|
9
|
+
static makeProvide: (str: string) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, StringConfig>>;
|
|
10
|
+
}
|
|
11
|
+
type APISupportedTypes = 'posts' | 'pages' | 'media' | 'categories' | 'tags' | 'settings';
|
|
12
|
+
declare const APIEndpointConfig_base: Context.TagClass<APIEndpointConfig, "APIEndpointConfig", {
|
|
13
|
+
readonly endpoint: string;
|
|
14
|
+
readonly type: APISupportedTypes;
|
|
15
|
+
readonly path?: string | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export declare class APIEndpointConfig extends APIEndpointConfig_base {
|
|
18
|
+
static makeLayer: (endpoint: string, type: APISupportedTypes, path?: string) => Layer.Layer<APIEndpointConfig, never, never>;
|
|
19
|
+
static makeProvide: (endpoint: string, type: APISupportedTypes, path?: string) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, APIEndpointConfig>>;
|
|
20
|
+
}
|
|
21
|
+
declare const DownloadImageConfig_base: Context.TagClass<DownloadImageConfig, "DownloadImageConfig", {
|
|
22
|
+
readonly imageUrl: string | URL;
|
|
23
|
+
readonly destination: string | URL;
|
|
24
|
+
}>;
|
|
25
|
+
export declare class DownloadImageConfig extends DownloadImageConfig_base {
|
|
26
|
+
static makeLayer: (imageUrl: string | URL, destination: string | URL) => Layer.Layer<DownloadImageConfig, never, never>;
|
|
27
|
+
static makeProvide: (imageUrl: string | URL, destination: string | URL) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, DownloadImageConfig>>;
|
|
28
|
+
}
|
|
29
|
+
declare const DownloadPostImageConfig_base: Context.TagClass<DownloadPostImageConfig, "DownloadPostImageConfig", {
|
|
30
|
+
readonly str: string;
|
|
31
|
+
readonly pathToFolder: string;
|
|
32
|
+
}>;
|
|
33
|
+
export declare class DownloadPostImageConfig extends DownloadPostImageConfig_base {
|
|
34
|
+
static makeLayer: (str: string, pathToFolder: string) => Layer.Layer<DownloadPostImageConfig, never, never>;
|
|
35
|
+
static makeProvide: (str: string, pathToFolder: string) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, DownloadPostImageConfig>>;
|
|
36
|
+
}
|
|
37
|
+
declare const ImportEndpointConfig_base: Context.TagClass<ImportEndpointConfig, "ImportEndpointConfig", {
|
|
38
|
+
readonly endpoint: string;
|
|
39
|
+
}>;
|
|
40
|
+
export declare class ImportEndpointConfig extends ImportEndpointConfig_base {
|
|
41
|
+
static makeLayer: (endpoint: string) => Layer.Layer<ImportEndpointConfig, never, never>;
|
|
42
|
+
static makeProvide: (endpoint: string) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ImportEndpointConfig>>;
|
|
43
|
+
}
|
|
44
|
+
declare const ImportPostsEndpointConfig_base: Context.TagClass<ImportPostsEndpointConfig, "ImportPostsEndpointConfig", {
|
|
45
|
+
readonly endpoint: string;
|
|
46
|
+
readonly useBlogPkg: boolean;
|
|
47
|
+
}>;
|
|
48
|
+
export declare class ImportPostsEndpointConfig extends ImportPostsEndpointConfig_base {
|
|
49
|
+
static makeLayer: (endpoint: string, useBlogPkg?: boolean) => Layer.Layer<ImportPostsEndpointConfig, never, never>;
|
|
50
|
+
static makeProvide: (endpoint: string, useBlogPkg?: boolean) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ImportPostsEndpointConfig>>;
|
|
51
|
+
}
|
|
52
|
+
declare const AstroAPIContextProvider_base: Context.TagClass<AstroAPIContextProvider, "AstroAPIContextProvider", {
|
|
53
|
+
context: APIContext;
|
|
54
|
+
}>;
|
|
55
|
+
export declare class AstroAPIContextProvider extends AstroAPIContextProvider_base {
|
|
56
|
+
static makeLayer: (context: APIContext) => Layer.Layer<AstroAPIContextProvider, never, never>;
|
|
57
|
+
static makeProvide: (context: APIContext) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, AstroAPIContextProvider>>;
|
|
58
|
+
}
|
|
59
|
+
declare const RawPageData_base: Context.TagClass<RawPageData, "RawPageData", {
|
|
60
|
+
readonly page: unknown;
|
|
61
|
+
}>;
|
|
62
|
+
export declare class RawPageData extends RawPageData_base {
|
|
63
|
+
static makeLayer: (page: unknown) => Layer.Layer<RawPageData, never, never>;
|
|
64
|
+
static makeProvide: (page: unknown) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, RawPageData>>;
|
|
65
|
+
}
|
|
66
|
+
declare const FullPageData_base: Context.TagClass<FullPageData, "FullPageData", {
|
|
67
|
+
readonly pageData: PageData;
|
|
68
|
+
}>;
|
|
69
|
+
export declare class FullPageData extends FullPageData_base {
|
|
70
|
+
static makeLayer: (pageData: PageData) => Layer.Layer<FullPageData, never, never>;
|
|
71
|
+
static makeProvide: (pageData: PageData) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, FullPageData>>;
|
|
72
|
+
}
|
|
73
|
+
declare const UseBlogPkgConfig_base: Context.TagClass<UseBlogPkgConfig, "UseBlogPkgConfig", {
|
|
74
|
+
readonly useBlogPkg: boolean;
|
|
75
|
+
}>;
|
|
76
|
+
export declare class UseBlogPkgConfig extends UseBlogPkgConfig_base {
|
|
77
|
+
static makeLayer: (useBlogPkg: boolean) => Layer.Layer<UseBlogPkgConfig, never, never>;
|
|
78
|
+
static makeProvide: (useBlogPkg: boolean) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, UseBlogPkgConfig>>;
|
|
79
|
+
}
|
|
80
|
+
declare const CategoryOrTagConfig_base: Context.TagClass<CategoryOrTagConfig, "CategoryOrTagConfig", {
|
|
81
|
+
readonly value: readonly number[];
|
|
82
|
+
}>;
|
|
83
|
+
export declare class CategoryOrTagConfig extends CategoryOrTagConfig_base {
|
|
84
|
+
static makeLayer: (value: readonly number[]) => Layer.Layer<CategoryOrTagConfig, never, never>;
|
|
85
|
+
static makeProvide: (value: readonly number[]) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, CategoryOrTagConfig>>;
|
|
86
|
+
}
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "studiocms/effect";
|
|
2
|
+
class StringConfig extends Context.Tag("StringConfig")() {
|
|
3
|
+
static makeLayer = (str) => Layer.succeed(
|
|
4
|
+
this,
|
|
5
|
+
this.of({
|
|
6
|
+
str
|
|
7
|
+
})
|
|
8
|
+
);
|
|
9
|
+
static makeProvide = (str) => Effect.provide(this.makeLayer(str));
|
|
10
|
+
}
|
|
11
|
+
const SUPPORTED_TYPES = ["posts", "pages", "media", "categories", "tags", "settings"];
|
|
12
|
+
class APIEndpointConfig extends Context.Tag("APIEndpointConfig")() {
|
|
13
|
+
static makeLayer = (endpoint, type, path) => {
|
|
14
|
+
if (!SUPPORTED_TYPES.includes(type)) {
|
|
15
|
+
throw new Error(`Invalid API type: ${type}. Supported types: ${SUPPORTED_TYPES.join(", ")}`);
|
|
16
|
+
}
|
|
17
|
+
return Layer.succeed(
|
|
18
|
+
this,
|
|
19
|
+
this.of({
|
|
20
|
+
endpoint,
|
|
21
|
+
type,
|
|
22
|
+
path
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
static makeProvide = (endpoint, type, path) => Effect.provide(this.makeLayer(endpoint, type, path));
|
|
27
|
+
}
|
|
28
|
+
class DownloadImageConfig extends Context.Tag("DownloadImageConfig")() {
|
|
29
|
+
static makeLayer = (imageUrl, destination) => Layer.succeed(
|
|
30
|
+
this,
|
|
31
|
+
this.of({
|
|
32
|
+
imageUrl,
|
|
33
|
+
destination
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
static makeProvide = (imageUrl, destination) => Effect.provide(this.makeLayer(imageUrl, destination));
|
|
37
|
+
}
|
|
38
|
+
class DownloadPostImageConfig extends Context.Tag("DownloadPostImageConfig")() {
|
|
39
|
+
static makeLayer = (str, pathToFolder) => Layer.succeed(
|
|
40
|
+
this,
|
|
41
|
+
this.of({
|
|
42
|
+
str,
|
|
43
|
+
pathToFolder
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
static makeProvide = (str, pathToFolder) => Effect.provide(this.makeLayer(str, pathToFolder));
|
|
47
|
+
}
|
|
48
|
+
class ImportEndpointConfig extends Context.Tag("ImportEndpointConfig")() {
|
|
49
|
+
static makeLayer = (endpoint) => Layer.succeed(this, this.of({ endpoint }));
|
|
50
|
+
static makeProvide = (endpoint) => Effect.provide(this.makeLayer(endpoint));
|
|
51
|
+
}
|
|
52
|
+
class ImportPostsEndpointConfig extends Context.Tag("ImportPostsEndpointConfig")() {
|
|
53
|
+
static makeLayer = (endpoint, useBlogPkg = false) => Layer.succeed(this, this.of({ endpoint, useBlogPkg }));
|
|
54
|
+
static makeProvide = (endpoint, useBlogPkg = false) => Effect.provide(this.makeLayer(endpoint, useBlogPkg));
|
|
55
|
+
}
|
|
56
|
+
class AstroAPIContextProvider extends Context.Tag("AstroAPIContextProvider")() {
|
|
57
|
+
static makeLayer = (context) => Layer.succeed(this, this.of({ context }));
|
|
58
|
+
static makeProvide = (context) => Effect.provide(this.makeLayer(context));
|
|
59
|
+
}
|
|
60
|
+
class RawPageData extends Context.Tag("RawPageData")() {
|
|
61
|
+
static makeLayer = (page) => Layer.succeed(this, this.of({ page }));
|
|
62
|
+
static makeProvide = (page) => Effect.provide(this.makeLayer(page));
|
|
63
|
+
}
|
|
64
|
+
class FullPageData extends Context.Tag("FullPageData")() {
|
|
65
|
+
static makeLayer = (pageData) => Layer.succeed(this, this.of({ pageData }));
|
|
66
|
+
static makeProvide = (pageData) => Effect.provide(this.makeLayer(pageData));
|
|
67
|
+
}
|
|
68
|
+
class UseBlogPkgConfig extends Context.Tag("UseBlogPkgConfig")() {
|
|
69
|
+
static makeLayer = (useBlogPkg) => Layer.succeed(this, this.of({ useBlogPkg }));
|
|
70
|
+
static makeProvide = (useBlogPkg) => Effect.provide(this.makeLayer(useBlogPkg));
|
|
71
|
+
}
|
|
72
|
+
class CategoryOrTagConfig extends Context.Tag("CategoryOrTagConfig")() {
|
|
73
|
+
static makeLayer = (value) => Layer.succeed(this, this.of({ value }));
|
|
74
|
+
static makeProvide = (value) => Effect.provide(this.makeLayer(value));
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
APIEndpointConfig,
|
|
78
|
+
AstroAPIContextProvider,
|
|
79
|
+
CategoryOrTagConfig,
|
|
80
|
+
DownloadImageConfig,
|
|
81
|
+
DownloadPostImageConfig,
|
|
82
|
+
FullPageData,
|
|
83
|
+
ImportEndpointConfig,
|
|
84
|
+
ImportPostsEndpointConfig,
|
|
85
|
+
RawPageData,
|
|
86
|
+
StringConfig,
|
|
87
|
+
UseBlogPkgConfig
|
|
88
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Effect } from 'studiocms/effect';
|
|
2
|
+
import type { CombinedInsertContent } from 'studiocms/sdk/types';
|
|
3
|
+
import { FullPageData, ImportEndpointConfig, RawPageData, UseBlogPkgConfig } from './configs.js';
|
|
4
|
+
import { WPAPIError } from './errors.js';
|
|
5
|
+
import { WordPressAPIUtils } from './utils.js';
|
|
6
|
+
declare const WordPressAPIConverters_base: Effect.Service.Class<WordPressAPIConverters, "WordPressAPIConverters", {
|
|
7
|
+
readonly dependencies: readonly [import("effect/Layer").Layer<WordPressAPIUtils, never, never>];
|
|
8
|
+
readonly effect: Effect.Effect<{
|
|
9
|
+
convertToPageData: Effect.Effect<{
|
|
10
|
+
readonly title: string;
|
|
11
|
+
readonly draft: boolean;
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly slug: string;
|
|
14
|
+
readonly categories: string;
|
|
15
|
+
readonly tags: string;
|
|
16
|
+
readonly description: string;
|
|
17
|
+
readonly package: string;
|
|
18
|
+
readonly showOnNav: boolean;
|
|
19
|
+
readonly publishedAt: string;
|
|
20
|
+
readonly updatedAt: string;
|
|
21
|
+
readonly contentLang: string;
|
|
22
|
+
readonly heroImage?: string | null | undefined;
|
|
23
|
+
readonly authorId: string;
|
|
24
|
+
readonly contributorIds: string;
|
|
25
|
+
readonly showAuthor: boolean;
|
|
26
|
+
readonly showContributors: boolean;
|
|
27
|
+
readonly parentFolder?: string | null | undefined;
|
|
28
|
+
readonly augments: string;
|
|
29
|
+
}, boolean | WPAPIError | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError, ImportEndpointConfig | RawPageData>;
|
|
30
|
+
convertToPageContent: Effect.Effect<CombinedInsertContent, boolean | WPAPIError | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError, RawPageData | FullPageData>;
|
|
31
|
+
convertToPostData: Effect.Effect<{
|
|
32
|
+
readonly title: string;
|
|
33
|
+
readonly draft: boolean;
|
|
34
|
+
readonly id: string;
|
|
35
|
+
readonly slug: string;
|
|
36
|
+
readonly categories: string;
|
|
37
|
+
readonly tags: string;
|
|
38
|
+
readonly description: string;
|
|
39
|
+
readonly package: string;
|
|
40
|
+
readonly showOnNav: boolean;
|
|
41
|
+
readonly publishedAt: string;
|
|
42
|
+
readonly updatedAt: string;
|
|
43
|
+
readonly contentLang: string;
|
|
44
|
+
readonly heroImage?: string | null | undefined;
|
|
45
|
+
readonly authorId: string;
|
|
46
|
+
readonly contributorIds: string;
|
|
47
|
+
readonly showAuthor: boolean;
|
|
48
|
+
readonly showContributors: boolean;
|
|
49
|
+
readonly parentFolder?: string | null | undefined;
|
|
50
|
+
readonly augments: string;
|
|
51
|
+
}, boolean | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError | import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, ImportEndpointConfig | RawPageData | UseBlogPkgConfig>;
|
|
52
|
+
convertToPostContent: Effect.Effect<CombinedInsertContent, boolean | WPAPIError | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError, RawPageData | FullPageData>;
|
|
53
|
+
}, import("effect/ConfigError").ConfigError | import("studiocms/sdk/base").DBClientInitializationError | import("studiocms/sdk/base").SDKInitializationError, WordPressAPIUtils>;
|
|
54
|
+
}>;
|
|
55
|
+
export declare class WordPressAPIConverters extends WordPressAPIConverters_base {
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { SDKCore } from "studiocms:sdk";
|
|
3
|
+
import { userProjectRoot } from "virtual:studiocms-devapps/config";
|
|
4
|
+
import { StudioCMSPageDataCategories, StudioCMSPageDataTags } from "@withstudiocms/sdk/tables";
|
|
5
|
+
import { Console, Effect, genLogger, Schema } from "studiocms/effect";
|
|
6
|
+
import { decode } from "studiocms/runtime";
|
|
7
|
+
import {
|
|
8
|
+
APIEndpointConfig,
|
|
9
|
+
CategoryOrTagConfig,
|
|
10
|
+
DownloadPostImageConfig,
|
|
11
|
+
FullPageData,
|
|
12
|
+
ImportEndpointConfig,
|
|
13
|
+
RawPageData,
|
|
14
|
+
StringConfig,
|
|
15
|
+
UseBlogPkgConfig
|
|
16
|
+
} from "./configs.js";
|
|
17
|
+
import { WPAPIError } from "./errors.js";
|
|
18
|
+
import { Page, Post } from "./schema.js";
|
|
19
|
+
import { WordPressAPIUtils } from "./utils.js";
|
|
20
|
+
const ASTRO_PUBLIC_FOLDER = path.resolve(userProjectRoot, "public");
|
|
21
|
+
const WPImportFolder = path.resolve(ASTRO_PUBLIC_FOLDER, "wp-import");
|
|
22
|
+
const pagesImagesFolder = path.resolve(WPImportFolder, "pages");
|
|
23
|
+
const postsImagesFolder = path.resolve(WPImportFolder, "posts");
|
|
24
|
+
const sharedMeta = (data) => ({
|
|
25
|
+
augments: "[]",
|
|
26
|
+
authorId: "",
|
|
27
|
+
categories: "[]",
|
|
28
|
+
tags: "[]",
|
|
29
|
+
contributorIds: "[]",
|
|
30
|
+
draft: data.status !== "publish",
|
|
31
|
+
heroImage: void 0,
|
|
32
|
+
parentFolder: void 0,
|
|
33
|
+
showAuthor: false,
|
|
34
|
+
showContributors: false
|
|
35
|
+
});
|
|
36
|
+
class WordPressAPIConverters extends Effect.Service()(
|
|
37
|
+
"WordPressAPIConverters",
|
|
38
|
+
{
|
|
39
|
+
dependencies: [WordPressAPIUtils.Default],
|
|
40
|
+
effect: genLogger("@studiocms/devapps/effects/WordPressAPI/converters.effect")(function* () {
|
|
41
|
+
const sdk = yield* SDKCore;
|
|
42
|
+
const {
|
|
43
|
+
apiEndpoint,
|
|
44
|
+
cleanUpHtml,
|
|
45
|
+
downloadAndUpdateImages,
|
|
46
|
+
downloadPostImage,
|
|
47
|
+
stripHtml,
|
|
48
|
+
turndown
|
|
49
|
+
} = yield* WordPressAPIUtils;
|
|
50
|
+
const _getCategoryById = sdk.dbService.withCodec({
|
|
51
|
+
decoder: Schema.UndefinedOr(StudioCMSPageDataCategories.Select),
|
|
52
|
+
encoder: Schema.Number,
|
|
53
|
+
callbackFn: (client, id) => client(
|
|
54
|
+
(db) => db.selectFrom("StudioCMSPageDataCategories").selectAll().where("id", "=", id).executeTakeFirst()
|
|
55
|
+
)
|
|
56
|
+
});
|
|
57
|
+
const _insertCategory = sdk.dbService.withEncoder({
|
|
58
|
+
encoder: Schema.Union(
|
|
59
|
+
Schema.Array(StudioCMSPageDataCategories.Insert),
|
|
60
|
+
StudioCMSPageDataCategories.Insert
|
|
61
|
+
),
|
|
62
|
+
callbackFn: (client, data) => client((db) => db.insertInto("StudioCMSPageDataCategories").values(data).execute())
|
|
63
|
+
});
|
|
64
|
+
const _getTagById = sdk.dbService.withCodec({
|
|
65
|
+
decoder: Schema.UndefinedOr(StudioCMSPageDataTags.Select),
|
|
66
|
+
encoder: Schema.Number,
|
|
67
|
+
callbackFn: (client, id) => client(
|
|
68
|
+
(db) => db.selectFrom("StudioCMSPageDataTags").selectAll().where("id", "=", id).executeTakeFirst()
|
|
69
|
+
)
|
|
70
|
+
});
|
|
71
|
+
const _insertTag = sdk.dbService.withEncoder({
|
|
72
|
+
encoder: Schema.Union(
|
|
73
|
+
Schema.Array(StudioCMSPageDataTags.Insert),
|
|
74
|
+
StudioCMSPageDataTags.Insert
|
|
75
|
+
),
|
|
76
|
+
callbackFn: (client, data) => client((db) => db.insertInto("StudioCMSPageDataTags").values(data).execute())
|
|
77
|
+
});
|
|
78
|
+
const convertToPageData = genLogger(
|
|
79
|
+
"@studiocms/devapps/effects/WordPressAPI/converters.effect.convertToPageData"
|
|
80
|
+
)(function* () {
|
|
81
|
+
const [{ endpoint }, { page }] = yield* Effect.all([ImportEndpointConfig, RawPageData]);
|
|
82
|
+
if (!endpoint) {
|
|
83
|
+
return yield* new WPAPIError({ message: "Missing endpoint configuration" });
|
|
84
|
+
}
|
|
85
|
+
if (!page) {
|
|
86
|
+
return yield* new WPAPIError({ message: "Missing page data" });
|
|
87
|
+
}
|
|
88
|
+
const data = yield* Schema.decodeUnknown(Page)(page);
|
|
89
|
+
const cleanHTML = yield* stripHtml.pipe(StringConfig.makeProvide(data.excerpt.rendered));
|
|
90
|
+
const titleImageId = data.featured_media;
|
|
91
|
+
if (!titleImageId || titleImageId === 0) {
|
|
92
|
+
yield* Console.log("No featured media for:", data.title.rendered);
|
|
93
|
+
const pageData2 = {
|
|
94
|
+
...sharedMeta(data),
|
|
95
|
+
id: crypto.randomUUID(),
|
|
96
|
+
title: data.title.rendered,
|
|
97
|
+
description: decode(cleanHTML),
|
|
98
|
+
slug: data.slug,
|
|
99
|
+
publishedAt: new Date(data.date_gmt).toISOString(),
|
|
100
|
+
updatedAt: new Date(data.modified_gmt).toISOString(),
|
|
101
|
+
showOnNav: false,
|
|
102
|
+
contentLang: "default",
|
|
103
|
+
package: "studiocms"
|
|
104
|
+
};
|
|
105
|
+
return pageData2;
|
|
106
|
+
}
|
|
107
|
+
const titleImageURL = yield* apiEndpoint.pipe(
|
|
108
|
+
APIEndpointConfig.makeProvide(endpoint, "media", String(titleImageId))
|
|
109
|
+
);
|
|
110
|
+
const titleImageResponse = yield* Effect.tryPromise(() => fetch(titleImageURL));
|
|
111
|
+
const titleImageJson = yield* Effect.tryPromise(() => titleImageResponse.json());
|
|
112
|
+
const titleImage = yield* downloadPostImage.pipe(
|
|
113
|
+
DownloadPostImageConfig.makeProvide(titleImageJson.source_url, pagesImagesFolder)
|
|
114
|
+
);
|
|
115
|
+
const pageData = {
|
|
116
|
+
...sharedMeta(data),
|
|
117
|
+
id: crypto.randomUUID(),
|
|
118
|
+
title: data.title.rendered,
|
|
119
|
+
description: decode(cleanHTML),
|
|
120
|
+
slug: data.slug,
|
|
121
|
+
publishedAt: new Date(data.date_gmt).toISOString(),
|
|
122
|
+
updatedAt: new Date(data.modified_gmt).toISOString(),
|
|
123
|
+
showOnNav: false,
|
|
124
|
+
contentLang: "default",
|
|
125
|
+
package: "studiocms",
|
|
126
|
+
heroImage: titleImage
|
|
127
|
+
};
|
|
128
|
+
return pageData;
|
|
129
|
+
});
|
|
130
|
+
const convertToPageContent = genLogger(
|
|
131
|
+
"@studiocms/devapps/effects/WordPressAPI/converters.effect.convertToPageContent"
|
|
132
|
+
)(function* () {
|
|
133
|
+
const [
|
|
134
|
+
{ page },
|
|
135
|
+
{
|
|
136
|
+
pageData: { id: pageId }
|
|
137
|
+
}
|
|
138
|
+
] = yield* Effect.all([RawPageData, FullPageData]);
|
|
139
|
+
const data = yield* Schema.decodeUnknown(Page)(page);
|
|
140
|
+
if (!pageId) {
|
|
141
|
+
return yield* new WPAPIError({ message: "pageData is missing id" });
|
|
142
|
+
}
|
|
143
|
+
const cleanUpContent = yield* cleanUpHtml.pipe(
|
|
144
|
+
StringConfig.makeProvide(data.content.rendered)
|
|
145
|
+
);
|
|
146
|
+
const htmlWithImages = yield* downloadAndUpdateImages.pipe(
|
|
147
|
+
DownloadPostImageConfig.makeProvide(cleanUpContent, pagesImagesFolder)
|
|
148
|
+
);
|
|
149
|
+
const content = yield* turndown.pipe(StringConfig.makeProvide(htmlWithImages));
|
|
150
|
+
const pageContent = {
|
|
151
|
+
contentLang: "default",
|
|
152
|
+
content
|
|
153
|
+
};
|
|
154
|
+
return pageContent;
|
|
155
|
+
});
|
|
156
|
+
const generateCategoriesOrTags = (type) => genLogger(
|
|
157
|
+
"@studiocms/devapps/effects/WordPressAPI/converters.effect.generateCategoriesOrTags"
|
|
158
|
+
)(function* () {
|
|
159
|
+
const [{ endpoint }, { value }] = yield* Effect.all([
|
|
160
|
+
ImportEndpointConfig,
|
|
161
|
+
CategoryOrTagConfig
|
|
162
|
+
]);
|
|
163
|
+
const TableFnMap = {
|
|
164
|
+
categories: _getCategoryById,
|
|
165
|
+
tags: _getTagById
|
|
166
|
+
};
|
|
167
|
+
const tableFn = TableFnMap[type];
|
|
168
|
+
const newItems = [];
|
|
169
|
+
const idChecks = yield* Effect.all(
|
|
170
|
+
value.map(
|
|
171
|
+
(val) => tableFn(val).pipe(Effect.map((exists) => ({ val, exists: !!exists })))
|
|
172
|
+
),
|
|
173
|
+
{ concurrency: 10 }
|
|
174
|
+
);
|
|
175
|
+
const missingIds = idChecks.filter(({ exists }) => !exists).map(({ val }) => val);
|
|
176
|
+
const fetchedIds = yield* Effect.all(
|
|
177
|
+
missingIds.map(
|
|
178
|
+
(id) => apiEndpoint.pipe(
|
|
179
|
+
APIEndpointConfig.makeProvide(endpoint, type, String(id)),
|
|
180
|
+
Effect.flatMap((url) => Effect.tryPromise(() => fetch(url))),
|
|
181
|
+
Effect.flatMap((response) => Effect.tryPromise(() => response.json()))
|
|
182
|
+
)
|
|
183
|
+
),
|
|
184
|
+
{ concurrency: 5 }
|
|
185
|
+
// Limit concurrent API calls
|
|
186
|
+
);
|
|
187
|
+
newItems.push(...fetchedIds);
|
|
188
|
+
if (newItems.length > 0) {
|
|
189
|
+
switch (type) {
|
|
190
|
+
case "categories": {
|
|
191
|
+
const data = newItems.map(
|
|
192
|
+
(category) => ({
|
|
193
|
+
id: category.id,
|
|
194
|
+
name: category.name,
|
|
195
|
+
slug: category.slug,
|
|
196
|
+
description: category.description,
|
|
197
|
+
meta: JSON.stringify(category.meta),
|
|
198
|
+
parent: category.parent || null
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
yield* Console.log(
|
|
202
|
+
"Inserting new Categories into the database:",
|
|
203
|
+
data.map((d) => `${d.id}: ${d.name}`).join(", ")
|
|
204
|
+
);
|
|
205
|
+
yield* _insertCategory(data);
|
|
206
|
+
yield* Console.log("Categories inserted!");
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case "tags": {
|
|
210
|
+
const tagData = newItems.map(
|
|
211
|
+
(tag) => ({
|
|
212
|
+
id: tag.id,
|
|
213
|
+
name: tag.name,
|
|
214
|
+
slug: tag.slug,
|
|
215
|
+
description: tag.description,
|
|
216
|
+
meta: JSON.stringify(tag.meta)
|
|
217
|
+
})
|
|
218
|
+
);
|
|
219
|
+
yield* Console.log(
|
|
220
|
+
"Inserting new Tags into the database:",
|
|
221
|
+
tagData.map((data) => `${data.id}: ${data.name}`).join(", ")
|
|
222
|
+
);
|
|
223
|
+
yield* _insertTag(tagData);
|
|
224
|
+
yield* Console.log("Tags inserted!");
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const convertToPostData = genLogger(
|
|
231
|
+
"@studiocms/devapps/effects/WordPressAPI/converters.effect.convertToPostData"
|
|
232
|
+
)(function* () {
|
|
233
|
+
const [{ endpoint }, { page: post }, { useBlogPkg }] = yield* Effect.all([
|
|
234
|
+
ImportEndpointConfig,
|
|
235
|
+
RawPageData,
|
|
236
|
+
UseBlogPkgConfig
|
|
237
|
+
]);
|
|
238
|
+
const data = yield* Schema.decodeUnknown(Post)(post);
|
|
239
|
+
const pkg = useBlogPkg ? "@studiocms/blog" : "studiocms/markdown";
|
|
240
|
+
const cleanedHTML = yield* stripHtml.pipe(StringConfig.makeProvide(data.excerpt.rendered));
|
|
241
|
+
const titleImageId = data.featured_media;
|
|
242
|
+
if (!titleImageId || titleImageId === 0) {
|
|
243
|
+
yield* Console.log("No featured media for:", data.title.rendered);
|
|
244
|
+
const pageData2 = {
|
|
245
|
+
...sharedMeta(data),
|
|
246
|
+
id: crypto.randomUUID(),
|
|
247
|
+
title: data.title.rendered,
|
|
248
|
+
description: decode(cleanedHTML),
|
|
249
|
+
slug: data.slug,
|
|
250
|
+
publishedAt: new Date(data.date_gmt).toISOString(),
|
|
251
|
+
updatedAt: new Date(data.modified_gmt).toISOString(),
|
|
252
|
+
showOnNav: false,
|
|
253
|
+
contentLang: "default",
|
|
254
|
+
package: pkg,
|
|
255
|
+
categories: JSON.stringify(data.categories),
|
|
256
|
+
tags: JSON.stringify(data.tags)
|
|
257
|
+
};
|
|
258
|
+
return pageData2;
|
|
259
|
+
}
|
|
260
|
+
const titleImageURL = yield* apiEndpoint.pipe(
|
|
261
|
+
APIEndpointConfig.makeProvide(endpoint, "media", String(titleImageId))
|
|
262
|
+
);
|
|
263
|
+
const titleImageResponse = yield* Effect.tryPromise(() => fetch(titleImageURL));
|
|
264
|
+
const titleImageJson = yield* Effect.tryPromise(() => titleImageResponse.json());
|
|
265
|
+
const titleImage = yield* downloadPostImage.pipe(
|
|
266
|
+
DownloadPostImageConfig.makeProvide(titleImageJson.source_url, postsImagesFolder)
|
|
267
|
+
);
|
|
268
|
+
yield* generateCategoriesOrTags("categories").pipe(
|
|
269
|
+
ImportEndpointConfig.makeProvide(endpoint),
|
|
270
|
+
CategoryOrTagConfig.makeProvide(data.categories)
|
|
271
|
+
);
|
|
272
|
+
yield* generateCategoriesOrTags("tags").pipe(
|
|
273
|
+
ImportEndpointConfig.makeProvide(endpoint),
|
|
274
|
+
CategoryOrTagConfig.makeProvide(data.tags)
|
|
275
|
+
);
|
|
276
|
+
const pageData = {
|
|
277
|
+
...sharedMeta(data),
|
|
278
|
+
id: crypto.randomUUID(),
|
|
279
|
+
title: data.title.rendered,
|
|
280
|
+
description: decode(cleanedHTML),
|
|
281
|
+
slug: data.slug,
|
|
282
|
+
publishedAt: new Date(data.date_gmt).toISOString(),
|
|
283
|
+
updatedAt: new Date(data.modified_gmt).toISOString(),
|
|
284
|
+
showOnNav: false,
|
|
285
|
+
contentLang: "default",
|
|
286
|
+
package: pkg,
|
|
287
|
+
categories: JSON.stringify(data.categories),
|
|
288
|
+
tags: JSON.stringify(data.tags),
|
|
289
|
+
heroImage: titleImage
|
|
290
|
+
};
|
|
291
|
+
return pageData;
|
|
292
|
+
});
|
|
293
|
+
const convertToPostContent = genLogger(
|
|
294
|
+
"@studiocms/devapps/effects/WordPressAPI/converters.effect.convertToPostContent"
|
|
295
|
+
)(function* () {
|
|
296
|
+
const [
|
|
297
|
+
{
|
|
298
|
+
pageData: { id: pageId }
|
|
299
|
+
},
|
|
300
|
+
{ page: post }
|
|
301
|
+
] = yield* Effect.all([FullPageData, RawPageData]);
|
|
302
|
+
const data = yield* Schema.decodeUnknown(Post)(post);
|
|
303
|
+
if (!pageId) {
|
|
304
|
+
return yield* new WPAPIError({ message: "pageData is missing id" });
|
|
305
|
+
}
|
|
306
|
+
const cleanupContent = yield* cleanUpHtml.pipe(
|
|
307
|
+
StringConfig.makeProvide(data.content.rendered)
|
|
308
|
+
);
|
|
309
|
+
const htmlWithImages = yield* downloadAndUpdateImages.pipe(
|
|
310
|
+
DownloadPostImageConfig.makeProvide(cleanupContent, postsImagesFolder)
|
|
311
|
+
);
|
|
312
|
+
const content = yield* turndown.pipe(StringConfig.makeProvide(htmlWithImages));
|
|
313
|
+
const pageContent = {
|
|
314
|
+
contentLang: "default",
|
|
315
|
+
content
|
|
316
|
+
};
|
|
317
|
+
return pageContent;
|
|
318
|
+
});
|
|
319
|
+
return {
|
|
320
|
+
convertToPageData,
|
|
321
|
+
convertToPageContent,
|
|
322
|
+
convertToPostData,
|
|
323
|
+
convertToPostContent
|
|
324
|
+
};
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
) {
|
|
328
|
+
}
|
|
329
|
+
export {
|
|
330
|
+
WordPressAPIConverters
|
|
331
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const WPAPIError_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 & {
|
|
2
|
+
readonly _tag: "WPAPIError";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
/**
|
|
5
|
+
* Error class for WordPress API related errors.
|
|
6
|
+
*/
|
|
7
|
+
export declare class WPAPIError extends WPAPIError_base<{
|
|
8
|
+
message: string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
}> {
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StudioCMSPageContent, StudioCMSPageData } from '@withstudiocms/sdk/tables';
|
|
2
|
+
import { Effect } from 'studiocms/effect';
|
|
3
|
+
import { ImportEndpointConfig, ImportPostsEndpointConfig } from './configs.js';
|
|
4
|
+
import { WordPressAPIConverters } from './converters.js';
|
|
5
|
+
import { WordPressAPIUtils } from './utils.js';
|
|
6
|
+
export type PageData = (typeof StudioCMSPageData)['Insert']['Type'];
|
|
7
|
+
export type PageContent = (typeof StudioCMSPageContent)['Insert']['Type'];
|
|
8
|
+
declare const WordPressAPI_base: Effect.Service.Class<WordPressAPI, "WordPressAPI", {
|
|
9
|
+
readonly dependencies: readonly [import("effect/Layer").Layer<WordPressAPIUtils, never, never>, import("effect/Layer").Layer<WordPressAPIConverters, import("effect/ConfigError").ConfigError | import("studiocms/sdk/base").DBClientInitializationError | import("studiocms/sdk/base").SDKInitializationError, never>];
|
|
10
|
+
readonly effect: Effect.Effect<{
|
|
11
|
+
importSettingsFromWPAPI: Effect.Effect<void, boolean | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError | import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, ImportEndpointConfig>;
|
|
12
|
+
importPagesFromWPAPI: Effect.Effect<void, boolean | import("./errors.js").WPAPIError | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError | import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, ImportEndpointConfig>;
|
|
13
|
+
importPostsFromWPAPI: Effect.Effect<void, boolean | import("./errors.js").WPAPIError | import("effect/ConfigError").ConfigError | import("astro/errors").AstroError | import("effect/Cause").UnknownException | import("effect/ParseResult").ParseError | import("@withstudiocms/kysely/client").DBCallbackFailure | import("@withstudiocms/kysely/core/errors").DatabaseError, ImportPostsEndpointConfig>;
|
|
14
|
+
}, import("effect/ConfigError").ConfigError | import("studiocms/sdk/base").DBClientInitializationError | import("studiocms/sdk/base").SDKInitializationError, WordPressAPIUtils | WordPressAPIConverters>;
|
|
15
|
+
}>;
|
|
16
|
+
export declare class WordPressAPI extends WordPressAPI_base {
|
|
17
|
+
static Provide: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, import("effect/ConfigError").ConfigError | import("studiocms/sdk/base").DBClientInitializationError | import("studiocms/sdk/base").SDKInitializationError | E, Exclude<R, WordPressAPI>>;
|
|
18
|
+
}
|
|
19
|
+
export {};
|