@paroicms/site-generator-plugin 0.15.1 → 0.16.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.
@@ -1,4 +1,4 @@
1
- import { messageOf } from "@paroi/data-formatters-lib";
1
+ import { messageOf } from "@paroicms/public-anywhere-lib";
2
2
  import { fetchWorkSession, loadStep } from "../db/db-read.queries.js";
3
3
  import { insertIssueEvent, updateSession } from "../db/db-write.queries.js";
4
4
  import { invokeMessageGuard } from "../generator/llm-queries/invoke-message-guard.js";
@@ -1,8 +1,8 @@
1
- import { strVal } from "@paroi/data-formatters-lib";
2
- import { resolveModuleDirectory } from "@paroicms/public-server-lib";
3
1
  import { readFileSync } from "node:fs";
4
2
  import { dirname, join } from "node:path";
3
+ import { resolveModuleDirectory } from "@paroicms/public-server-lib";
4
+ import { type } from "arktype";
5
5
  export const projectDir = resolveModuleDirectory(import.meta.url, { parent: true });
6
6
  export const packageDir = dirname(projectDir);
7
- export const pluginVersion = strVal(JSON.parse(readFileSync(join(packageDir, "package.json"), "utf-8")).version);
7
+ export const pluginVersion = type({ version: "string", "+": "ignore" }).assert(JSON.parse(readFileSync(join(packageDir, "package.json"), "utf-8"))).version;
8
8
  export const SLUG = "site-generator";
@@ -1,82 +1,144 @@
1
- import { boolVal, isObj, nbVal, strVal, strValOrUndef } from "@paroi/data-formatters-lib";
1
+ import { isObj } from "@paroicms/public-anywhere-lib";
2
2
  import { ApiError } from "@paroicms/public-server-lib";
3
- export function formatGeneratorPluginConfiguration(pluginConf) {
4
- const anthropicApiKey = strValOrUndef(pluginConf.anthropicApiKey, { varName: "anthropicApiKey" });
5
- const mistralApiKey = strValOrUndef(pluginConf.mistralApiKey, { varName: "mistralApiKey" });
6
- const packName = strValOrUndef(pluginConf.packName, { varName: "packName" });
7
- const debugDir = strValOrUndef(pluginConf.debugDir, { varName: "debugDir" });
8
- if (!anthropicApiKey || !mistralApiKey || !packName) {
9
- throw new Error(`Invalid configuration for plugin "@paroicms/site-generator-plugin"`);
3
+ import { type } from "arktype";
4
+ export const GeneratorPluginConfigurationAT = type({
5
+ anthropicApiKey: "string",
6
+ mistralApiKey: "string",
7
+ packName: "string",
8
+ "googleRecaptchaSiteKey?": "string|undefined",
9
+ "debugDir?": "string|undefined",
10
+ "+": "reject",
11
+ }).pipe((data) => data);
12
+ const BaseCommandAT = type({
13
+ command: "string",
14
+ "+": "ignore",
15
+ });
16
+ const NewSessionCommandAT = type({
17
+ command: '"newSession"',
18
+ language: "string",
19
+ recaptchaToken: "string",
20
+ "+": "reject",
21
+ });
22
+ const RenewSessionCommandAT = type({
23
+ command: '"renewSession"',
24
+ sessionToken: "string",
25
+ recaptchaToken: "string",
26
+ "+": "reject",
27
+ });
28
+ const SetLanguageCommandAT = type({
29
+ command: '"setLanguage"',
30
+ sessionToken: "string",
31
+ language: "string",
32
+ "+": "reject",
33
+ });
34
+ const LoadWorkSessionCommandAT = type({
35
+ command: '"loadWorkSession"',
36
+ sessionToken: "string",
37
+ "+": "reject",
38
+ });
39
+ const LoadStepCommandAT = type({
40
+ command: '"loadStep"',
41
+ sessionToken: "string",
42
+ stepNumber: "number",
43
+ "+": "reject",
44
+ });
45
+ const CreateSiteSchemaCommandAT = type({
46
+ command: '"createSiteSchema"',
47
+ sessionToken: "string",
48
+ prompt: "string",
49
+ "+": "reject",
50
+ });
51
+ const UpdateSiteSchemaCommandAT = type({
52
+ command: '"updateSiteSchema"',
53
+ sessionToken: "string",
54
+ prompt: "string",
55
+ fromStepNumber: "number",
56
+ "+": "reject",
57
+ });
58
+ const GenerateSiteCommandAT = type({
59
+ command: '"generateSite"',
60
+ sessionToken: "string",
61
+ fromStepNumber: "number",
62
+ withSampleData: "boolean",
63
+ "+": "reject",
64
+ });
65
+ const PromptAT = type("string").narrow((prompt) => {
66
+ if (prompt.length > 5000) {
67
+ throw new ApiError("Prompt is too long", 400);
10
68
  }
11
- return { anthropicApiKey, mistralApiKey, packName, debugDir };
12
- }
69
+ return true;
70
+ });
13
71
  export function formatGeneratorCommand(data) {
14
72
  if (!isObj(data))
15
73
  throw new ApiError("Invalid input", 400);
16
- const command = strVal(data.command, { varName: "command" });
74
+ const baseCommand = BaseCommandAT.assert(data);
75
+ const command = baseCommand.command;
17
76
  if (command === "newSession") {
77
+ const validated = NewSessionCommandAT.assert(data);
18
78
  return {
19
79
  command: "newSession",
20
- language: strVal(data.language, { varName: "language" }),
21
- recaptchaToken: strVal(data.recaptchaToken, { varName: "recaptchaToken" }),
80
+ language: validated.language,
81
+ recaptchaToken: validated.recaptchaToken,
22
82
  };
23
83
  }
24
84
  if (command === "renewSession") {
85
+ const validated = RenewSessionCommandAT.assert(data);
25
86
  return {
26
87
  command: "renewSession",
27
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
28
- recaptchaToken: strVal(data.recaptchaToken, { varName: "recaptchaToken" }),
88
+ sessionToken: validated.sessionToken,
89
+ recaptchaToken: validated.recaptchaToken,
29
90
  };
30
91
  }
31
92
  if (command === "setLanguage") {
93
+ const validated = SetLanguageCommandAT.assert(data);
32
94
  return {
33
95
  command: "setLanguage",
34
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
35
- language: strVal(data.language, { varName: "language" }),
96
+ sessionToken: validated.sessionToken,
97
+ language: validated.language,
36
98
  };
37
99
  }
38
100
  if (command === "loadWorkSession") {
101
+ const validated = LoadWorkSessionCommandAT.assert(data);
39
102
  return {
40
103
  command: "loadWorkSession",
41
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
104
+ sessionToken: validated.sessionToken,
42
105
  };
43
106
  }
44
107
  if (command === "loadStep") {
108
+ const validated = LoadStepCommandAT.assert(data);
45
109
  return {
46
110
  command: "loadStep",
47
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
48
- stepNumber: nbVal(data.stepNumber, { varName: "stepNumber" }),
111
+ sessionToken: validated.sessionToken,
112
+ stepNumber: validated.stepNumber,
49
113
  };
50
114
  }
51
115
  if (command === "createSiteSchema") {
116
+ const validated = CreateSiteSchemaCommandAT.assert(data);
117
+ const prompt = PromptAT.assert(validated.prompt);
52
118
  return {
53
119
  command: "createSiteSchema",
54
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
55
- prompt: formatPrompt(data.prompt),
120
+ sessionToken: validated.sessionToken,
121
+ prompt,
56
122
  };
57
123
  }
58
124
  if (command === "updateSiteSchema") {
125
+ const validated = UpdateSiteSchemaCommandAT.assert(data);
126
+ const prompt = PromptAT.assert(validated.prompt);
59
127
  return {
60
128
  command: "updateSiteSchema",
61
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
62
- prompt: formatPrompt(data.prompt),
63
- fromStepNumber: nbVal(data.fromStepNumber),
129
+ sessionToken: validated.sessionToken,
130
+ prompt,
131
+ fromStepNumber: validated.fromStepNumber,
64
132
  };
65
133
  }
66
134
  if (command === "generateSite") {
135
+ const validated = GenerateSiteCommandAT.assert(data);
67
136
  return {
68
137
  command: "generateSite",
69
- sessionToken: strVal(data.sessionToken, { varName: "sessionToken" }),
70
- fromStepNumber: nbVal(data.fromStepNumber),
71
- withSampleData: boolVal(data.withSampleData, { varName: "withSampleData" }),
138
+ sessionToken: validated.sessionToken,
139
+ fromStepNumber: validated.fromStepNumber,
140
+ withSampleData: validated.withSampleData,
72
141
  };
73
142
  }
74
143
  throw new ApiError(`Invalid command: ${command}`, 400);
75
144
  }
76
- function formatPrompt(val) {
77
- const prompt = strVal(val, { varName: "prompt" });
78
- if (prompt.length > 5000) {
79
- throw new ApiError("Prompt is too long", 400);
80
- }
81
- return prompt;
82
- }
@@ -1,5 +1,5 @@
1
- import { createOrOpenSqliteConnection, createSqlLogger, getMetadataDbSchemaVersion, } from "@paroicms/internal-server-lib";
2
1
  import { join } from "node:path";
2
+ import { createOrOpenSqliteConnection, createSqlLogger, getMetadataDbSchemaVersion, } from "@paroicms/internal-server-lib";
3
3
  import { projectDir } from "../context.js";
4
4
  import { currentDbSchemaVersion, dbSchemaName, migrateSiteGeneratorDb } from "./ddl-migration.js";
5
5
  export async function createOrOpenSiteGeneratorConnection({ sqliteFile, canCreate, logger, }) {
@@ -1,5 +1,12 @@
1
- import { dateVal, nbVal, strVal, strValOrUndef } from "@paroi/data-formatters-lib";
1
+ import { parseSqliteDateTime } from "@paroicms/internal-server-lib";
2
+ import { type } from "arktype";
2
3
  import { ensureType, formatActivityCode, formatStepKind, formatStepStatus } from "./formatters.js";
4
+ const SessionRowAT = type({
5
+ id: "string",
6
+ expireAt: "string|number|Date",
7
+ successStepCount: "number",
8
+ "+": "reject",
9
+ });
3
10
  export async function getInvalidSessionError(ctx, sessionId) {
4
11
  const { cn } = ctx;
5
12
  const row = await cn("PgSession as s")
@@ -10,13 +17,19 @@ export async function getInvalidSessionError(ctx, sessionId) {
10
17
  .first();
11
18
  if (!row)
12
19
  return "not found";
13
- const successStepCount = nbVal(row.successStepCount);
14
- if (successStepCount >= 20)
20
+ const validated = SessionRowAT.assert(row);
21
+ if (validated.successStepCount >= 20)
15
22
  return "too many steps";
16
- const expireAt = dateVal(row.expireAt).getTime();
23
+ const expireAt = parseSqliteDateTime(validated.expireAt).getTime();
17
24
  if (expireAt < Date.now())
18
25
  return "expired";
19
26
  }
27
+ const StepSchemaRowAT = type({
28
+ siteSchema: "string",
29
+ l10n: "string",
30
+ localizedValues: "string",
31
+ "+": "reject",
32
+ });
20
33
  export async function readStepSchema(ctx, stepNumber) {
21
34
  const { cn, sessionId } = ctx;
22
35
  const row = await cn("PgSchemaStep")
@@ -25,12 +38,20 @@ export async function readStepSchema(ctx, stepNumber) {
25
38
  .first();
26
39
  if (!row)
27
40
  throw new Error(`[${sessionId}] Step "${stepNumber}" not found`);
41
+ const validated = StepSchemaRowAT.assert(row);
28
42
  return {
29
- siteSchema: JSON.parse(strVal(row.siteSchema)),
30
- l10n: JSON.parse(strVal(row.l10n)),
31
- localizedValues: JSON.parse(strVal(row.localizedValues)),
43
+ siteSchema: JSON.parse(validated.siteSchema),
44
+ l10n: JSON.parse(validated.l10n),
45
+ localizedValues: JSON.parse(validated.localizedValues),
32
46
  };
33
47
  }
48
+ const WorkSessionRowAT = type({
49
+ id: "string",
50
+ createdAt: "string|number|Date",
51
+ expireAt: "string|number|Date",
52
+ language: "string",
53
+ "+": "reject",
54
+ });
34
55
  export async function fetchWorkSession(ctx) {
35
56
  const { cn, sessionId } = ctx;
36
57
  const row = await cn("PgSession")
@@ -40,12 +61,13 @@ export async function fetchWorkSession(ctx) {
40
61
  if (!row) {
41
62
  throw new Error(`Session not found: ${sessionId}`);
42
63
  }
64
+ const validated = WorkSessionRowAT.assert(row);
43
65
  const steps = await loadSessionSteps(ctx);
44
66
  return {
45
- id: strVal(row.id),
46
- createdAt: dateVal(row.createdAt).toISOString(),
47
- expireAt: dateVal(row.expireAt).toISOString(),
48
- language: strVal(row.language),
67
+ id: validated.id,
68
+ createdAt: parseSqliteDateTime(validated.createdAt).toISOString(),
69
+ expireAt: parseSqliteDateTime(validated.expireAt).toISOString(),
70
+ language: validated.language,
49
71
  steps,
50
72
  };
51
73
  }
@@ -78,51 +100,90 @@ function buildStepsQuery(cn) {
78
100
  "i.sessionId": "s.sessionId",
79
101
  });
80
102
  }
103
+ const StepRowAT = type({
104
+ stepNumber: "number",
105
+ explanation: "string|null",
106
+ status: "string",
107
+ kind: "string",
108
+ currentActivity: "string|null",
109
+ promptTitle: "string|null",
110
+ siteSchema: "string|null",
111
+ l10n: "string|null",
112
+ schemaLocalizedValues: "string|null",
113
+ siteId: "string|null",
114
+ siteLocalizedValues: "string|null",
115
+ siteUrl: "string|null",
116
+ loginEmail: "string|null",
117
+ loginPassword: "string|null",
118
+ "+": "reject",
119
+ }).pipe((r) => ({
120
+ ...r,
121
+ explanation: r.explanation ?? undefined,
122
+ currentActivity: r.currentActivity ?? undefined,
123
+ promptTitle: r.promptTitle ?? undefined,
124
+ siteSchema: r.siteSchema ?? undefined,
125
+ l10n: r.l10n ?? undefined,
126
+ schemaLocalizedValues: r.schemaLocalizedValues ?? undefined,
127
+ siteId: r.siteId ?? undefined,
128
+ siteLocalizedValues: r.siteLocalizedValues ?? undefined,
129
+ siteUrl: r.siteUrl ?? undefined,
130
+ loginEmail: r.loginEmail ?? undefined,
131
+ loginPassword: r.loginPassword ?? undefined,
132
+ }));
81
133
  function mapRowToStep(row, sessionId) {
134
+ const validated = StepRowAT.assert(row);
82
135
  const baseStep = {
83
- stepNumber: nbVal(row.stepNumber),
84
- explanation: strValOrUndef(row.explanation),
136
+ stepNumber: validated.stepNumber,
137
+ explanation: validated.explanation,
85
138
  };
86
- const status = formatStepStatus(row.status);
87
- const kind = formatStepKind(row.kind);
139
+ const status = formatStepStatus(validated.status);
140
+ const kind = formatStepKind(validated.kind);
88
141
  if (status === "pending") {
89
142
  return ensureType({
90
143
  ...baseStep,
91
144
  status,
92
145
  kind,
93
- currentActivity: formatActivityCode(row.currentActivity),
146
+ currentActivity: formatActivityCode(validated.currentActivity),
94
147
  });
95
148
  }
96
149
  if (status === "completed") {
97
150
  if (kind === "initialSchema" || kind === "updateSchema") {
98
- if (!row.siteSchema) {
99
- throw new Error(`[Session "${sessionId}"] PgSchemaStep row is missing for completed step "${row.stepNumber}"`);
151
+ if (!validated.siteSchema) {
152
+ throw new Error(`[Session "${sessionId}"] PgSchemaStep row is missing for completed step "${validated.stepNumber}"`);
153
+ }
154
+ if (!validated.l10n || !validated.schemaLocalizedValues) {
155
+ throw new Error(`[Session "${sessionId}"] Missing schema data for completed step "${validated.stepNumber}"`);
100
156
  }
101
157
  return ensureType({
102
158
  ...baseStep,
103
159
  status,
104
160
  kind,
105
- promptTitle: strValOrUndef(row.promptTitle),
106
- siteSchema: JSON.parse(strVal(row.siteSchema)),
107
- l10n: JSON.parse(strVal(row.l10n)),
108
- localizedValues: JSON.parse(strVal(row.schemaLocalizedValues)),
161
+ promptTitle: validated.promptTitle,
162
+ siteSchema: JSON.parse(validated.siteSchema),
163
+ l10n: JSON.parse(validated.l10n),
164
+ localizedValues: JSON.parse(validated.schemaLocalizedValues),
109
165
  });
110
166
  }
111
167
  if (kind === "generateSite") {
112
- if (!row.siteId) {
113
- throw new Error(`[Session "${sessionId}"] PgGeneratedSiteStep row is missing for completed step "${row.stepNumber}"`);
168
+ if (!validated.siteId) {
169
+ throw new Error(`[Session "${sessionId}"] PgGeneratedSiteStep row is missing for completed step "${validated.stepNumber}"`);
170
+ }
171
+ if (!validated.siteUrl ||
172
+ !validated.loginEmail ||
173
+ !validated.loginPassword ||
174
+ !validated.siteLocalizedValues) {
175
+ throw new Error(`[Session "${sessionId}"] Missing generated site data for completed step "${validated.stepNumber}"`);
114
176
  }
115
- const siteUrl = strVal(row.siteUrl);
116
177
  return ensureType({
117
178
  ...baseStep,
118
179
  status,
119
180
  kind,
120
- siteId: strVal(row.siteId),
121
- siteUrl,
122
- adminUiUrl: `${siteUrl}/adm`,
123
- loginEmail: strVal(row.loginEmail),
124
- loginPassword: strVal(row.loginPassword),
125
- localizedValues: JSON.parse(strVal(row.siteLocalizedValues)),
181
+ siteId: validated.siteId,
182
+ siteUrl: validated.siteUrl,
183
+ adminUiUrl: `${validated.siteUrl}/adm`,
184
+ loginEmail: validated.loginEmail,
185
+ loginPassword: validated.loginPassword,
186
+ localizedValues: JSON.parse(validated.siteLocalizedValues),
126
187
  });
127
188
  }
128
189
  throw new Error(`[Session "${sessionId}"] invalid step kind "${kind}"`);
@@ -1,5 +1,5 @@
1
- import { strVal } from "@paroi/data-formatters-lib";
2
1
  import { sqliteDateTime } from "@paroicms/internal-server-lib";
2
+ import { type } from "arktype";
3
3
  export async function insertSession(ctx, values) {
4
4
  const { cn } = ctx;
5
5
  await cn("PgSession").insert({
@@ -128,6 +128,7 @@ export async function updateGeneratedSiteStepSetAsCompleted(ctx, stepHandle, val
128
128
  });
129
129
  });
130
130
  }
131
+ const InsertedAT = type({ id: "string", "+": "reject" });
131
132
  export async function insertIssueEvent(ctx, values) {
132
133
  const { cn, sessionId } = ctx;
133
134
  const [inserted] = await cn("PgIssueEvent")
@@ -140,5 +141,5 @@ export async function insertIssueEvent(ctx, values) {
140
141
  siteId: values.siteId,
141
142
  })
142
143
  .returning("id");
143
- return { id: strVal(inserted.id) };
144
+ return InsertedAT.assert(inserted);
144
145
  }
@@ -1,46 +1,24 @@
1
- import { strVal, strValOrUndef } from "@paroi/data-formatters-lib";
1
+ import { type } from "arktype";
2
2
  export function ensureType(value) {
3
3
  return value;
4
4
  }
5
+ const StepKindAT = type('"initialSchema"|"updateSchema"|"generateSite"');
5
6
  export function formatStepKind(value) {
6
- const v = strVal(value);
7
- if (v === "initialSchema" || v === "updateSchema" || v === "generateSite") {
8
- return v;
9
- }
10
- throw new Error(`Invalid step kind "${v}"`);
7
+ return StepKindAT.assert(value);
11
8
  }
9
+ const SchemaStepKindAT = type('"initialSchema"|"updateSchema"');
12
10
  export function formatSchemaStepKind(value) {
13
- const v = strVal(value);
14
- if (v === "initialSchema" || v === "updateSchema") {
15
- return v;
16
- }
17
- throw new Error(`Invalid schema step kind "${v}"`);
11
+ return SchemaStepKindAT.assert(value);
18
12
  }
13
+ const GeneratedSiteStepKindAT = type('"generateSite"');
19
14
  export function formatGeneratedSiteStepKind(value) {
20
- const v = strVal(value);
21
- if (v === "generateSite") {
22
- return v;
23
- }
24
- throw new Error(`Invalid generated site step kind "${v}"`);
15
+ return GeneratedSiteStepKindAT.assert(value);
25
16
  }
17
+ const StepStatusAT = type('"completed"|"pending"|"failed"|"noEffect"');
26
18
  export function formatStepStatus(value) {
27
- const v = strVal(value);
28
- if (v === "completed" || v === "pending" || v === "failed" || v === "noEffect") {
29
- return v;
30
- }
31
- throw new Error(`Invalid step status "${v}"`);
19
+ return StepStatusAT.assert(value);
32
20
  }
21
+ const ActivityCodeAT = type('"initial1"|"initial2"|"updating1"|"updating2"|"generatingSite"|"generatingContent"|undefined');
33
22
  export function formatActivityCode(value) {
34
- const v = strValOrUndef(value);
35
- if (v === undefined)
36
- return;
37
- if (v === "initial1" ||
38
- v === "initial2" ||
39
- v === "updating1" ||
40
- v === "updating2" ||
41
- v === "generatingSite" ||
42
- v === "generatingContent") {
43
- return v;
44
- }
45
- throw new Error(`Invalid activity code "${v}"`);
23
+ return ActivityCodeAT.assert(value);
46
24
  }
@@ -1,4 +1,4 @@
1
- import { messageOf } from "@paroi/data-formatters-lib";
1
+ import { messageOf } from "@paroicms/public-anywhere-lib";
2
2
  let seq = 0;
3
3
  export async function batchInvokeMinistral(ctx, prompts, options) {
4
4
  const startTime = Date.now();
@@ -1,6 +1,6 @@
1
- import { connectorPackageDir } from "@paroicms/connector";
2
1
  import { readFile } from "node:fs/promises";
3
2
  import { join } from "node:path";
3
+ import { connectorPackageDir } from "@paroicms/connector";
4
4
  import { projectDir } from "../../context.js";
5
5
  import { buildPromptTemplate } from "./prompt-template.js";
6
6
  const contextContent = await readPromptFile("0-context.md");
@@ -1,5 +1,5 @@
1
- import { messageOf } from "@paroi/data-formatters-lib";
2
1
  import { ensureDirectory } from "@paroicms/internal-server-lib";
2
+ import { messageOf } from "@paroicms/public-anywhere-lib";
3
3
  import { readFile, writeFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
5
  import { estimateTokenCount } from "./llm-tokens.js";
@@ -1,4 +1,4 @@
1
- import { messageOf } from "@paroi/data-formatters-lib";
1
+ import { messageOf } from "@paroicms/public-anywhere-lib";
2
2
  import { insertIssueEvent, updateStep } from "../../db/db-write.queries.js";
3
3
  export function safeCallStep(ctx, stepHandle, cb) {
4
4
  void safeCallStepExec(ctx, stepHandle, cb);
@@ -1,4 +1,4 @@
1
- import { messageOf } from "@paroi/data-formatters-lib";
1
+ import { messageOf } from "@paroicms/public-anywhere-lib";
2
2
  export function createTaskCollector(ctx) {
3
3
  const tasks = [];
4
4
  return {
@@ -1,4 +1,4 @@
1
- import { boolVal, listValOrUndef, strVal, strValOrUndef, } from "@paroi/data-formatters-lib";
1
+ import { type } from "arktype";
2
2
  import { insertIssueEvent } from "../../db/db-write.queries.js";
3
3
  import { invokeClaude } from "../lib/calling-llm-anthropic.js";
4
4
  import { createPromptTemplate } from "../lib/create-prompt.js";
@@ -7,7 +7,13 @@ import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js";
7
7
  const guardPrompt = await createPromptTemplate({
8
8
  filename: "message-guard.md",
9
9
  });
10
- const invalidCauses = new Set(["rude", "malicious", "outOfScope", "technicalLimits", "noSense"]);
10
+ const MessageGuardReportAT = type({
11
+ "language?": "string|undefined",
12
+ valid: "boolean",
13
+ "causes?": '("rude"|"malicious"|"outOfScope"|"technicalLimits"|"noSense")[]|undefined',
14
+ "explanation?": "string|undefined",
15
+ "+": "reject",
16
+ });
11
17
  export async function invokeMessageGuard(ctx, input, { skipOutOfScopeCheck = false } = {}) {
12
18
  const llmTaskName = "guard";
13
19
  const llmInput = {
@@ -34,7 +40,7 @@ export async function invokeMessageGuard(ctx, input, { skipOutOfScopeCheck = fal
34
40
  format: "yaml",
35
41
  },
36
42
  ]);
37
- const report = formatMessageGuardReport(rawReport.guard);
43
+ const report = MessageGuardReportAT.assert(rawReport.guard);
38
44
  if (report.causes && skipOutOfScopeCheck) {
39
45
  report.causes = report.causes.filter((cause) => cause !== "outOfScope");
40
46
  if (report.causes.length === 0) {
@@ -89,17 +95,3 @@ function getCauseLabel(cause, language) {
89
95
  return cause;
90
96
  }
91
97
  }
92
- function formatMessageGuardReport(rawReport) {
93
- return {
94
- language: strValOrUndef(rawReport.language, { varName: "language" }),
95
- valid: boolVal(rawReport.valid, { varName: "valid" }),
96
- causes: listValOrUndef(rawReport.causes, formatGuardInvalidCause),
97
- explanation: strValOrUndef(rawReport.explanation, { varName: "explanation" }),
98
- };
99
- }
100
- function formatGuardInvalidCause(cause) {
101
- const v = strVal(cause, { varName: "cause" });
102
- if (!invalidCauses.has(v))
103
- throw new Error(`Invalid cause: "${v}"`);
104
- return v;
105
- }
@@ -1,7 +1,7 @@
1
- import { generateSlug } from "@paroicms/public-anywhere-lib";
2
1
  import { randomUUID } from "node:crypto";
3
2
  import { mkdir, writeFile } from "node:fs/promises";
4
3
  import { join } from "node:path";
4
+ import { generateSlug } from "@paroicms/public-anywhere-lib";
5
5
  import { loadStep, readStepSchema } from "../../db/db-read.queries.js";
6
6
  import { insertStep, saveGeneratedSiteStep, } from "../../db/db-write.queries.js";
7
7
  import { fillSiteWithFakeContent } from "../fake-content-generator/create-database-with-fake-content.js";
@@ -1,7 +1,7 @@
1
+ import { join } from "node:path";
1
2
  import Anthropic from "@anthropic-ai/sdk";
2
3
  import { Mistral } from "@mistralai/mistralai";
3
4
  import { readOrCreateJwtSecretSync } from "@paroicms/internal-server-lib";
4
- import { join } from "node:path";
5
5
  export function createRawContext(service, options) {
6
6
  const { cn, logNextQuery, pluginConf, debugDir } = options;
7
7
  const packConf = service.connector.getSitePackConf(pluginConf.packName);
@@ -1,10 +1,10 @@
1
- import { messageOf } from "@paroi/data-formatters-lib";
2
1
  import { pathExists } from "@paroicms/internal-server-lib";
2
+ import { messageOf } from "@paroicms/public-anywhere-lib";
3
3
  import { ApiError, escapeHtml, makeStylesheetLinkAsyncTag, } from "@paroicms/public-server-lib";
4
4
  import { join } from "node:path";
5
5
  import { executeCommand } from "./commands/execute-command.js";
6
6
  import { SLUG, packageDir, pluginVersion } from "./context.js";
7
- import { formatGeneratorCommand, formatGeneratorPluginConfiguration } from "./data-format.js";
7
+ import { GeneratorPluginConfigurationAT, formatGeneratorCommand } from "./data-format.js";
8
8
  import { createOrOpenSiteGeneratorConnection } from "./db/db-init.js";
9
9
  import { initializeImageNames } from "./generator/lib/images-lib.js";
10
10
  import { createRawContext } from "./lib/create-raw-context.js";
@@ -19,7 +19,7 @@ const plugin = {
19
19
  canCreate: true,
20
20
  logger: service.logger,
21
21
  });
22
- const pluginConf = formatGeneratorPluginConfiguration(service.configuration);
22
+ const pluginConf = GeneratorPluginConfigurationAT.assert(service.configuration);
23
23
  let debugDir = pluginConf.debugDir;
24
24
  if (debugDir) {
25
25
  if (!(await pathExists(debugDir))) {
@@ -47,7 +47,7 @@ const plugin = {
47
47
  return;
48
48
  return [
49
49
  makeStylesheetLinkAsyncTag(`${service.pluginAssetsUrl}/gen-front.css`),
50
- `<script type="module" src="${escapeHtml(`${service.pluginAssetsUrl}/gen-front.mjs`)}" class="js-script-${SLUG}" data-google-recaptcha-site-key="${escapeHtml(service.configuration.googleRecaptchaSiteKey)}" async></script>`,
50
+ `<script type="module" src="${escapeHtml(`${service.pluginAssetsUrl}/gen-front.mjs`)}" class="js-script-${SLUG}" data-google-recaptcha-site-key="${escapeHtml(pluginConf.googleRecaptchaSiteKey)}" async></script>`,
51
51
  ];
52
52
  });
53
53
  service.setPublicApiHandler(async (service, httpContext, relativePath) => {
@@ -64,6 +64,7 @@ const plugin = {
64
64
  command = formatGeneratorCommand(req.body);
65
65
  }
66
66
  catch (error) {
67
+ service.logger.error("Invalid command:", error);
67
68
  res.status(400).send({ status: 400, message: messageOf(error) });
68
69
  return;
69
70
  }