@respectify/astro-moderation 0.1.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.
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/integration.d.ts +12 -0
- package/dist/integration.js +36 -0
- package/dist/moderate.d.ts +8 -0
- package/dist/moderate.js +145 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.js +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Respectify
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @respectify/astro-moderation
|
|
2
|
+
|
|
3
|
+
Thin Astro integration for [Respectify](https://respectify.ai) comment moderation.
|
|
4
|
+
|
|
5
|
+
Respectify does more than just comment moderation — it provides a complete solution for managing and enhancing user-generated content. It monitors for tone, logical fallacies, and spam and educates commenters on how to improve their comments.
|
|
6
|
+
|
|
7
|
+
Add the integration, set two env vars, then call `moderateComment()` from your own actions or API routes. **No comment UI, no database, no Astro Actions wiring.**
|
|
8
|
+
|
|
9
|
+
Want hosted Astro comments (UI + DB)? Use [`@respectify/astro`](https://www.npmjs.com/package/@respectify/astro) instead.
|
|
10
|
+
API-only outside Astro? Use [`@respectify/client`](https://www.npmjs.com/package/@respectify/client).
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @respectify/astro-moderation @respectify/client
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// astro.config.mjs
|
|
22
|
+
import { defineConfig } from "astro/config";
|
|
23
|
+
import respectifyModeration from "@respectify/astro-moderation";
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
integrations: [
|
|
27
|
+
respectifyModeration({
|
|
28
|
+
mode: "full", // or "spam-only" | "perspective"
|
|
29
|
+
toxicityThreshold: 0.7,
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```env
|
|
36
|
+
RESPECTIFY_EMAIL=you@example.com
|
|
37
|
+
RESPECTIFY_API_KEY=your-api-key
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Moderate a comment
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// e.g. src/pages/api/comments.ts or an Astro Action
|
|
44
|
+
import { moderateComment } from "@respectify/astro-moderation";
|
|
45
|
+
|
|
46
|
+
const result = await moderateComment({
|
|
47
|
+
comment: userText,
|
|
48
|
+
topicUrl: Astro.site ? new URL(`/blog/${slug}`, Astro.site).toString() : undefined,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (!result.approved) {
|
|
52
|
+
return { ok: false, feedback: result.feedback };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// save/publish the comment yourself
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Modes
|
|
59
|
+
|
|
60
|
+
| Mode | Behaviour |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `full` (default) | Spam check + comment score when topic context is available |
|
|
63
|
+
| `spam-only` | Spam detection only |
|
|
64
|
+
| `perspective` | Perspective-compatible toxicity / insult / profanity scores |
|
|
65
|
+
|
|
66
|
+
### Tip: cache `articleId`
|
|
67
|
+
|
|
68
|
+
`moderateComment()` returns `articleId` when it initializes a topic. Reuse it for later comments on the same page to avoid re-init:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const result = await moderateComment({
|
|
72
|
+
comment: userText,
|
|
73
|
+
articleId: cachedArticleIdForThisPost,
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Compared to `@respectify/astro`
|
|
78
|
+
|
|
79
|
+
| | `@respectify/astro-moderation` | `@respectify/astro` |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| Purpose | Moderate existing comments | Full comments product |
|
|
82
|
+
| UI | Yours | Included |
|
|
83
|
+
| Database | Yours | Astro DB |
|
|
84
|
+
| Setup | Integration + 2 env vars | DB + actions + component |
|
|
85
|
+
|
|
86
|
+
## Links
|
|
87
|
+
|
|
88
|
+
- Product: https://respectify.ai
|
|
89
|
+
- Comment moderation API guide: https://respectify.ai/comment-moderation-api
|
|
90
|
+
- Client SDK: https://www.npmjs.com/package/@respectify/client
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default } from "./integration.js";
|
|
2
|
+
export { default as respectifyModeration } from "./integration.js";
|
|
3
|
+
export { moderateComment, getModerationDefaults, setModerationDefaults } from "./moderate.js";
|
|
4
|
+
export type { ModerateCommentInput, ModerateCommentResult, ModerateMode, RespectifyAstroModerationOptions, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AstroIntegration } from "astro";
|
|
2
|
+
import type { RespectifyAstroModerationOptions } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Thin Astro integration for Respectify moderation.
|
|
5
|
+
*
|
|
6
|
+
* Adds env schema for RESPECTIFY_EMAIL / RESPECTIFY_API_KEY and stores
|
|
7
|
+
* default options used by moderateComment().
|
|
8
|
+
*
|
|
9
|
+
* Does NOT inject comment UI, database schema, or Astro Actions —
|
|
10
|
+
* you keep your existing comment stack and call moderateComment() from it.
|
|
11
|
+
*/
|
|
12
|
+
export default function respectifyModeration(options?: RespectifyAstroModerationOptions): AstroIntegration;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { envField } from "astro/config";
|
|
2
|
+
import { setModerationDefaults } from "./moderate.js";
|
|
3
|
+
/**
|
|
4
|
+
* Thin Astro integration for Respectify moderation.
|
|
5
|
+
*
|
|
6
|
+
* Adds env schema for RESPECTIFY_EMAIL / RESPECTIFY_API_KEY and stores
|
|
7
|
+
* default options used by moderateComment().
|
|
8
|
+
*
|
|
9
|
+
* Does NOT inject comment UI, database schema, or Astro Actions —
|
|
10
|
+
* you keep your existing comment stack and call moderateComment() from it.
|
|
11
|
+
*/
|
|
12
|
+
export default function respectifyModeration(options = {}) {
|
|
13
|
+
setModerationDefaults(options);
|
|
14
|
+
return {
|
|
15
|
+
name: "@respectify/astro-moderation",
|
|
16
|
+
hooks: {
|
|
17
|
+
"astro:config:setup": ({ updateConfig, logger }) => {
|
|
18
|
+
updateConfig({
|
|
19
|
+
env: {
|
|
20
|
+
schema: {
|
|
21
|
+
RESPECTIFY_EMAIL: envField.string({
|
|
22
|
+
context: "server",
|
|
23
|
+
access: "secret",
|
|
24
|
+
}),
|
|
25
|
+
RESPECTIFY_API_KEY: envField.string({
|
|
26
|
+
context: "server",
|
|
27
|
+
access: "secret",
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
logger.info(`Respectify moderation ready (mode=${options.mode ?? "full"}). Call moderateComment() from your actions/API routes.`);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ModerateCommentInput, ModerateCommentResult, RespectifyAstroModerationOptions } from "./types.js";
|
|
2
|
+
export declare function setModerationDefaults(options: RespectifyAstroModerationOptions): void;
|
|
3
|
+
export declare function getModerationDefaults(): RespectifyAstroModerationOptions;
|
|
4
|
+
/**
|
|
5
|
+
* Moderate a single comment with Respectify.
|
|
6
|
+
* Call from an Astro Action, API route, or server endpoint.
|
|
7
|
+
*/
|
|
8
|
+
export declare function moderateComment(input: ModerateCommentInput): Promise<ModerateCommentResult>;
|
package/dist/moderate.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { RespectifyClient, AuthenticationError, PaymentRequiredError, RespectifyError, } from "@respectify/client";
|
|
2
|
+
const articleIdCache = new Map();
|
|
3
|
+
let client = null;
|
|
4
|
+
let integrationDefaults = {};
|
|
5
|
+
export function setModerationDefaults(options) {
|
|
6
|
+
integrationDefaults = { ...options };
|
|
7
|
+
}
|
|
8
|
+
export function getModerationDefaults() {
|
|
9
|
+
return integrationDefaults;
|
|
10
|
+
}
|
|
11
|
+
function getClient() {
|
|
12
|
+
if (client)
|
|
13
|
+
return client;
|
|
14
|
+
const email = process.env.RESPECTIFY_EMAIL;
|
|
15
|
+
const apiKey = process.env.RESPECTIFY_API_KEY;
|
|
16
|
+
if (!email || !apiKey) {
|
|
17
|
+
throw new Error("Respectify credentials missing. Set RESPECTIFY_EMAIL and RESPECTIFY_API_KEY.");
|
|
18
|
+
}
|
|
19
|
+
client = new RespectifyClient({ email, apiKey });
|
|
20
|
+
return client;
|
|
21
|
+
}
|
|
22
|
+
async function resolveArticleId(input) {
|
|
23
|
+
if (input.articleId)
|
|
24
|
+
return input.articleId;
|
|
25
|
+
const topicUrl = input.topicUrl ?? integrationDefaults.defaultTopicUrl;
|
|
26
|
+
const topicText = input.topicText;
|
|
27
|
+
const cacheKey = topicUrl ? `url:${topicUrl}` : topicText ? `text:${topicText.slice(0, 200)}` : null;
|
|
28
|
+
if (!cacheKey)
|
|
29
|
+
return undefined;
|
|
30
|
+
const cached = articleIdCache.get(cacheKey);
|
|
31
|
+
if (cached)
|
|
32
|
+
return cached;
|
|
33
|
+
const respectify = getClient();
|
|
34
|
+
const init = topicUrl
|
|
35
|
+
? await respectify.initTopicFromUrl(topicUrl)
|
|
36
|
+
: await respectify.initTopicFromText(topicText);
|
|
37
|
+
articleIdCache.set(cacheKey, init.article_id);
|
|
38
|
+
return init.article_id;
|
|
39
|
+
}
|
|
40
|
+
function decideFromToxicity(toxicityScore, threshold, extras) {
|
|
41
|
+
if (extras?.isSpam) {
|
|
42
|
+
return {
|
|
43
|
+
approved: false,
|
|
44
|
+
feedback: "This comment appears to be spam.",
|
|
45
|
+
toxicityScore,
|
|
46
|
+
isSpam: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (toxicityScore !== undefined && toxicityScore >= threshold) {
|
|
50
|
+
return {
|
|
51
|
+
approved: false,
|
|
52
|
+
feedback: extras?.explanation || "This comment looks too disrespectful to publish as-is.",
|
|
53
|
+
toxicityScore,
|
|
54
|
+
isSpam: false,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
approved: true,
|
|
59
|
+
feedback: "Looks good.",
|
|
60
|
+
toxicityScore,
|
|
61
|
+
isSpam: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function perspectiveScores(response) {
|
|
65
|
+
if (!response?.attributeScores)
|
|
66
|
+
return undefined;
|
|
67
|
+
const out = {};
|
|
68
|
+
for (const [name, entry] of Object.entries(response.attributeScores)) {
|
|
69
|
+
out[name] = entry.summaryScore.value;
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Moderate a single comment with Respectify.
|
|
75
|
+
* Call from an Astro Action, API route, or server endpoint.
|
|
76
|
+
*/
|
|
77
|
+
export async function moderateComment(input) {
|
|
78
|
+
const mode = input.mode ?? integrationDefaults.mode ?? "full";
|
|
79
|
+
const toxicityThreshold = input.toxicityThreshold ?? integrationDefaults.toxicityThreshold ?? 0.7;
|
|
80
|
+
try {
|
|
81
|
+
const respectify = getClient();
|
|
82
|
+
if (mode === "perspective") {
|
|
83
|
+
const response = await respectify.perspective.analyzeComment({
|
|
84
|
+
comment: { text: input.comment },
|
|
85
|
+
requestedAttributes: {
|
|
86
|
+
TOXICITY: {},
|
|
87
|
+
INSULT: {},
|
|
88
|
+
PROFANITY: {},
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
const scores = perspectiveScores(response);
|
|
92
|
+
const toxicityScore = scores?.TOXICITY;
|
|
93
|
+
return {
|
|
94
|
+
...decideFromToxicity(toxicityScore, toxicityThreshold),
|
|
95
|
+
perspectiveScores: scores,
|
|
96
|
+
raw: response,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const articleId = await resolveArticleId(input);
|
|
100
|
+
if (mode === "spam-only") {
|
|
101
|
+
const spam = await respectify.checkSpam(input.comment, articleId);
|
|
102
|
+
return {
|
|
103
|
+
approved: !spam.is_spam,
|
|
104
|
+
feedback: spam.is_spam
|
|
105
|
+
? spam.reasoning || "This comment appears to be spam."
|
|
106
|
+
: "Looks good.",
|
|
107
|
+
isSpam: spam.is_spam,
|
|
108
|
+
articleId,
|
|
109
|
+
raw: spam,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// full
|
|
113
|
+
const megacallOptions = {
|
|
114
|
+
comment: input.comment,
|
|
115
|
+
includeSpam: true,
|
|
116
|
+
};
|
|
117
|
+
if (articleId) {
|
|
118
|
+
megacallOptions.articleId = articleId;
|
|
119
|
+
megacallOptions.includeCommentScore = true;
|
|
120
|
+
}
|
|
121
|
+
const result = await respectify.megacall(megacallOptions);
|
|
122
|
+
const toxicityScore = result.comment_score?.toxicity_score;
|
|
123
|
+
const explanation = result.comment_score?.toxicity_explanation;
|
|
124
|
+
return {
|
|
125
|
+
...decideFromToxicity(toxicityScore, toxicityThreshold, {
|
|
126
|
+
isSpam: result.spam_check?.is_spam,
|
|
127
|
+
explanation,
|
|
128
|
+
}),
|
|
129
|
+
articleId,
|
|
130
|
+
raw: result,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (error instanceof AuthenticationError) {
|
|
135
|
+
throw new Error("Respectify authentication failed. Check RESPECTIFY_EMAIL and RESPECTIFY_API_KEY.");
|
|
136
|
+
}
|
|
137
|
+
if (error instanceof PaymentRequiredError) {
|
|
138
|
+
throw new Error("Respectify payment required. Top up your account balance.");
|
|
139
|
+
}
|
|
140
|
+
if (error instanceof RespectifyError) {
|
|
141
|
+
throw new Error(`Respectify API error (${error.statusCode ?? "unknown"}): ${error.message}`);
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type ModerateMode = "full" | "spam-only" | "perspective";
|
|
2
|
+
export interface RespectifyAstroModerationOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Which analysis path to use by default.
|
|
5
|
+
* - full: spam + comment score (topic context when URL/text provided)
|
|
6
|
+
* - spam-only: spam check only
|
|
7
|
+
* - perspective: Perspective-compatible toxicity attribute scores
|
|
8
|
+
* @default "full"
|
|
9
|
+
*/
|
|
10
|
+
mode?: ModerateMode;
|
|
11
|
+
/**
|
|
12
|
+
* Toxicity block threshold for auto-decision (0–1). Higher = more toxic.
|
|
13
|
+
* Used when mode is "full" or "perspective".
|
|
14
|
+
* @default 0.7
|
|
15
|
+
*/
|
|
16
|
+
toxicityThreshold?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Optional default page/topic URL used to build article context when
|
|
19
|
+
* moderateComment() is called without topicUrl/topicText.
|
|
20
|
+
*/
|
|
21
|
+
defaultTopicUrl?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ModerateCommentInput {
|
|
24
|
+
/** Comment text to analyse */
|
|
25
|
+
comment: string;
|
|
26
|
+
/** Existing Respectify article/topic UUID (skips init when set) */
|
|
27
|
+
articleId?: string;
|
|
28
|
+
/** Initialize topic from this URL when articleId is missing */
|
|
29
|
+
topicUrl?: string;
|
|
30
|
+
/** Initialize topic from this text when articleId / topicUrl missing */
|
|
31
|
+
topicText?: string;
|
|
32
|
+
/** Override integration default mode for this call */
|
|
33
|
+
mode?: ModerateMode;
|
|
34
|
+
/** Override toxicity threshold for this call */
|
|
35
|
+
toxicityThreshold?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface ModerateCommentResult {
|
|
38
|
+
/** Whether the comment should be allowed through */
|
|
39
|
+
approved: boolean;
|
|
40
|
+
/** Short reason / coaching feedback for the commenter or your logs */
|
|
41
|
+
feedback: string;
|
|
42
|
+
/** Toxicity-ish score when available (0 = clean, 1 = highly toxic) */
|
|
43
|
+
toxicityScore?: number;
|
|
44
|
+
/** True when spam was detected */
|
|
45
|
+
isSpam?: boolean;
|
|
46
|
+
/** Article context used (useful to cache for later comments on the same page) */
|
|
47
|
+
articleId?: string;
|
|
48
|
+
/** Perspective attribute scores when mode is "perspective" */
|
|
49
|
+
perspectiveScores?: Record<string, number>;
|
|
50
|
+
/** Underlying megacall / perspective payload for advanced callers */
|
|
51
|
+
raw?: unknown;
|
|
52
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@respectify/astro-moderation",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Thin Astro integration for Respectify comment moderation — API key in, approve/block + feedback out.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Respectify <dave@respectify.ai>",
|
|
8
|
+
"homepage": "https://www.npmjs.com/package/@respectify/astro-moderation",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Respectify/respectify-astro-moderation.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Respectify/respectify-astro-moderation/issues"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"astro",
|
|
21
|
+
"astro-integration",
|
|
22
|
+
"withastro",
|
|
23
|
+
"respectify",
|
|
24
|
+
"moderation",
|
|
25
|
+
"comments",
|
|
26
|
+
"toxicity",
|
|
27
|
+
"spam",
|
|
28
|
+
"perspective-api"
|
|
29
|
+
],
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./moderate": {
|
|
43
|
+
"types": "./dist/moderate.d.ts",
|
|
44
|
+
"import": "./dist/moderate.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc -p tsconfig.json",
|
|
49
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
50
|
+
"prepublishOnly": "npm run build"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@respectify/client": "^0.5.0",
|
|
54
|
+
"astro": "^5.0.0 || ^6.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@respectify/client": "^0.5.0",
|
|
58
|
+
"@types/node": "^26.1.1",
|
|
59
|
+
"astro": "^5.16.5",
|
|
60
|
+
"typescript": "^5.9.2"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=18"
|
|
64
|
+
}
|
|
65
|
+
}
|