@nexpress/core 0.3.7 → 0.3.9
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/dist/{audit-43OLHR3U.js → audit-ZLNKBIDO.js} +3 -3
- package/dist/auth.js +4 -4
- package/dist/{can-UJ2NAOIR.js → can-U5F4JBZ7.js} +2 -2
- package/dist/{chunk-OMGQZ4Q5.js → chunk-2OWUHCFY.js} +2 -2
- package/dist/{chunk-OMGQZ4Q5.js.map → chunk-2OWUHCFY.js.map} +1 -1
- package/dist/{chunk-ELK6AVW5.js → chunk-2X3GBJOT.js} +2 -2
- package/dist/{chunk-HNX7COHQ.js → chunk-3SW4L3DL.js} +12 -12
- package/dist/chunk-3SW4L3DL.js.map +1 -0
- package/dist/{chunk-ML2E3P3X.js → chunk-5C22NDW4.js} +2 -2
- package/dist/chunk-5C22NDW4.js.map +1 -0
- package/dist/{chunk-RKM4GDWM.js → chunk-6MRTH734.js} +1 -1
- package/dist/chunk-6MRTH734.js.map +1 -0
- package/dist/{chunk-PW43RCJK.js → chunk-6OUWW6JF.js} +2 -2
- package/dist/{chunk-QBIJZZ5V.js → chunk-CGLJBRRX.js} +2 -2
- package/dist/chunk-CGLJBRRX.js.map +1 -0
- package/dist/{chunk-2VZZ7M26.js → chunk-EAYUAXW3.js} +3 -3
- package/dist/chunk-EAYUAXW3.js.map +1 -0
- package/dist/{chunk-2N53KKIL.js → chunk-EWVXP3GP.js} +2 -2
- package/dist/{chunk-CAS4Z6IN.js → chunk-I4FSVEJK.js} +1 -1
- package/dist/chunk-I4FSVEJK.js.map +1 -0
- package/dist/{chunk-LN6NTH6E.js → chunk-K4CJ3KXB.js} +3 -3
- package/dist/chunk-K4CJ3KXB.js.map +1 -0
- package/dist/{chunk-B7DTNT4O.js → chunk-MWLSXK6Y.js} +2 -2
- package/dist/{chunk-NFHS7CFV.js → chunk-Q7MK5ZKG.js} +2 -2
- package/dist/{chunk-PUV3VZPD.js → chunk-QZ52U4ET.js} +2 -2
- package/dist/{chunk-2GXH7566.js → chunk-SJ7M2VCC.js} +10 -10
- package/dist/chunk-SJ7M2VCC.js.map +1 -0
- package/dist/{chunk-6UV2P5MW.js → chunk-TIWJVQOO.js} +3 -3
- package/dist/chunk-TIWJVQOO.js.map +1 -0
- package/dist/{chunk-MLXKZK6G.js → chunk-TSCXXBOM.js} +76 -28
- package/dist/chunk-TSCXXBOM.js.map +1 -0
- package/dist/{chunk-L6VG7IK6.js → chunk-VBVLYFSZ.js} +2 -2
- package/dist/chunk-VBVLYFSZ.js.map +1 -0
- package/dist/{chunk-RDTTK27V.js → chunk-XPD7EQML.js} +3 -3
- package/dist/chunk-XPD7EQML.js.map +1 -0
- package/dist/{chunk-RJ76SKWQ.js → chunk-XU2GJJ6Z.js} +1 -1
- package/dist/chunk-XU2GJJ6Z.js.map +1 -0
- package/dist/{chunk-WJJ5MBH5.js → chunk-YEOQJ7WW.js} +1 -1
- package/dist/chunk-YEOQJ7WW.js.map +1 -0
- package/dist/community.js +14 -14
- package/dist/{config-YHUEYQ66.js → config-YDGNUDKP.js} +5 -5
- package/dist/{digest-ZODDTXA2.js → digest-IWHMJPXI.js} +4 -4
- package/dist/{host-XBGYIQEE.js → host-HG4QGD3L.js} +4 -4
- package/dist/i18n.js +2 -2
- package/dist/index.js +21 -21
- package/dist/index.js.map +1 -1
- package/dist/{job-log-N3IGI4NA.js → job-log-UY6ERPQZ.js} +3 -3
- package/dist/jobs.js +3 -3
- package/dist/{logger-2WUTTELV.js → logger-6ZGEKEMK.js} +2 -2
- package/dist/media.js +3 -3
- package/dist/{mentions-U4JACYI6.js → mentions-LQRZWAGO.js} +2 -2
- package/dist/{mutes-MNQP6ACF.js → mutes-PQA6U5X7.js} +2 -2
- package/dist/{notification-prefs-H4HFVCL7.js → notification-prefs-62NX2GBF.js} +2 -2
- package/dist/observability.js +2 -2
- package/dist/{reputation-ICIXDGPM.js → reputation-5DJLDBZY.js} +3 -3
- package/dist/{scheduled-S6IO47JD.js → scheduled-C2IKVZVK.js} +5 -5
- package/dist/seo.js +4 -4
- package/dist/{settings-OZWM6L2K.js → settings-NBAP7E5E.js} +2 -2
- package/dist/{strings-4EWJYDOG.js → strings-O2M7VSKV.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-2GXH7566.js.map +0 -1
- package/dist/chunk-2VZZ7M26.js.map +0 -1
- package/dist/chunk-6UV2P5MW.js.map +0 -1
- package/dist/chunk-CAS4Z6IN.js.map +0 -1
- package/dist/chunk-HNX7COHQ.js.map +0 -1
- package/dist/chunk-L6VG7IK6.js.map +0 -1
- package/dist/chunk-LN6NTH6E.js.map +0 -1
- package/dist/chunk-ML2E3P3X.js.map +0 -1
- package/dist/chunk-MLXKZK6G.js.map +0 -1
- package/dist/chunk-QBIJZZ5V.js.map +0 -1
- package/dist/chunk-RDTTK27V.js.map +0 -1
- package/dist/chunk-RJ76SKWQ.js.map +0 -1
- package/dist/chunk-RKM4GDWM.js.map +0 -1
- package/dist/chunk-WJJ5MBH5.js.map +0 -1
- /package/dist/{audit-43OLHR3U.js.map → audit-ZLNKBIDO.js.map} +0 -0
- /package/dist/{can-UJ2NAOIR.js.map → can-U5F4JBZ7.js.map} +0 -0
- /package/dist/{chunk-ELK6AVW5.js.map → chunk-2X3GBJOT.js.map} +0 -0
- /package/dist/{chunk-PW43RCJK.js.map → chunk-6OUWW6JF.js.map} +0 -0
- /package/dist/{chunk-2N53KKIL.js.map → chunk-EWVXP3GP.js.map} +0 -0
- /package/dist/{chunk-B7DTNT4O.js.map → chunk-MWLSXK6Y.js.map} +0 -0
- /package/dist/{chunk-NFHS7CFV.js.map → chunk-Q7MK5ZKG.js.map} +0 -0
- /package/dist/{chunk-PUV3VZPD.js.map → chunk-QZ52U4ET.js.map} +0 -0
- /package/dist/{config-YHUEYQ66.js.map → config-YDGNUDKP.js.map} +0 -0
- /package/dist/{digest-ZODDTXA2.js.map → digest-IWHMJPXI.js.map} +0 -0
- /package/dist/{host-XBGYIQEE.js.map → host-HG4QGD3L.js.map} +0 -0
- /package/dist/{job-log-N3IGI4NA.js.map → job-log-UY6ERPQZ.js.map} +0 -0
- /package/dist/{logger-2WUTTELV.js.map → logger-6ZGEKEMK.js.map} +0 -0
- /package/dist/{mentions-U4JACYI6.js.map → mentions-LQRZWAGO.js.map} +0 -0
- /package/dist/{mutes-MNQP6ACF.js.map → mutes-PQA6U5X7.js.map} +0 -0
- /package/dist/{notification-prefs-H4HFVCL7.js.map → notification-prefs-62NX2GBF.js.map} +0 -0
- /package/dist/{reputation-ICIXDGPM.js.map → reputation-5DJLDBZY.js.map} +0 -0
- /package/dist/{scheduled-S6IO47JD.js.map → scheduled-C2IKVZVK.js.map} +0 -0
- /package/dist/{settings-OZWM6L2K.js.map → settings-NBAP7E5E.js.map} +0 -0
- /package/dist/{strings-4EWJYDOG.js.map → strings-O2M7VSKV.js.map} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listAuditEvents,
|
|
3
3
|
recordAuditEvent
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5C22NDW4.js";
|
|
5
5
|
import "./chunk-SBCVAC2Z.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-Q7MK5ZKG.js";
|
|
7
7
|
import "./chunk-XANPEOJC.js";
|
|
8
8
|
import "./chunk-X7K5F2UI.js";
|
|
9
9
|
import "./chunk-PZ5AY32C.js";
|
|
@@ -11,4 +11,4 @@ export {
|
|
|
11
11
|
listAuditEvents,
|
|
12
12
|
recordAuditEvent
|
|
13
13
|
};
|
|
14
|
-
//# sourceMappingURL=audit-
|
|
14
|
+
//# sourceMappingURL=audit-ZLNKBIDO.js.map
|
package/dist/auth.js
CHANGED
|
@@ -38,16 +38,16 @@ import {
|
|
|
38
38
|
verifyPassword,
|
|
39
39
|
verifyToken,
|
|
40
40
|
verifyTokenFull
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-TIWJVQOO.js";
|
|
42
42
|
import {
|
|
43
43
|
can
|
|
44
44
|
} from "./chunk-EQ2Z3KMD.js";
|
|
45
|
-
import "./chunk-
|
|
46
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-5C22NDW4.js";
|
|
46
|
+
import "./chunk-6MRTH734.js";
|
|
47
47
|
import "./chunk-SBCVAC2Z.js";
|
|
48
48
|
import "./chunk-ZCINJSS4.js";
|
|
49
49
|
import "./chunk-OROPGO65.js";
|
|
50
|
-
import "./chunk-
|
|
50
|
+
import "./chunk-Q7MK5ZKG.js";
|
|
51
51
|
import "./chunk-XANPEOJC.js";
|
|
52
52
|
import "./chunk-X7K5F2UI.js";
|
|
53
53
|
import "./chunk-PZ5AY32C.js";
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
isMemberBanned,
|
|
4
4
|
memberCan,
|
|
5
5
|
withMemberWrite
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XU2GJJ6Z.js";
|
|
7
7
|
import "./chunk-U4QCCLAW.js";
|
|
8
8
|
import "./chunk-SBCVAC2Z.js";
|
|
9
9
|
import "./chunk-ZCINJSS4.js";
|
|
@@ -16,4 +16,4 @@ export {
|
|
|
16
16
|
memberCan,
|
|
17
17
|
withMemberWrite
|
|
18
18
|
};
|
|
19
|
-
//# sourceMappingURL=can-
|
|
19
|
+
//# sourceMappingURL=can-U5F4JBZ7.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPluginRegistration
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TSCXXBOM.js";
|
|
4
4
|
import {
|
|
5
5
|
getCurrentSiteId
|
|
6
6
|
} from "./chunk-SBCVAC2Z.js";
|
|
@@ -319,4 +319,4 @@ export {
|
|
|
319
319
|
setPluginConfig,
|
|
320
320
|
pluginConfigCacheTag
|
|
321
321
|
};
|
|
322
|
-
//# sourceMappingURL=chunk-
|
|
322
|
+
//# sourceMappingURL=chunk-2OWUHCFY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins/config.ts","../src/themes/settings-schema.ts"],"sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport type { ZodTypeAny } from \"zod\";\n\nimport { getDb } from \"../db/index.js\";\nimport { npSettings } from \"../db/schema/system.js\";\nimport { NpValidationError } from \"../errors.js\";\nimport { getCurrentSiteId } from \"../sites/context.js\";\nimport { getPluginRegistration } from \"./host.js\";\nimport {\n introspectThemeSettingsSchema,\n type NpThemeSettingsField,\n} from \"../themes/settings-schema.js\";\n\nconst DEFAULT_SITE = \"default\";\nconst CONFIG_KEY_PREFIX = \"plugin.config:\";\n\n/**\n * G.1 — per-plugin operator config.\n *\n * Stored at `np_settings.(site_id, key=\"plugin.config:<pluginId>\")`.\n * Mirrors theme settings storage exactly, including the `__npVersion` /\n * `__npSettings` envelope, so a future shared `getCachedSetting<T>(key)`\n * helper can read both surfaces. Cache invalidation rides a new\n * `np:plugin:<id>` tag (see `packages/next/src/cache.ts`).\n *\n * Per locked decision E (`docs/design/plugin-config-auto-form.md` § 2):\n * we store under `np_settings`, NOT `np_plugins.config` (the legacy\n * column was dropped in the same migration that introduced this module).\n */\n\nfunction configKey(pluginId: string): string {\n return `${CONFIG_KEY_PREFIX}${pluginId}`;\n}\n\n/**\n * Versioned envelope shape for persisted plugin config — identical to the\n * theme `NpVersionedSettings` shape. Two parallel definitions instead of a\n * shared one because (a) themes and plugins share zero schema surface\n * otherwise, (b) the type is only ~5 lines, and (c) collapsing them would\n * couple `themes/` and `plugins/` modules without functional benefit.\n */\nexport interface NpVersionedPluginConfig {\n __npVersion: number;\n __npSettings: unknown;\n}\n\nexport function isVersionedPluginConfig(\n value: unknown,\n): value is NpVersionedPluginConfig {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Partial<NpVersionedPluginConfig>;\n return (\n typeof candidate.__npVersion === \"number\" &&\n Number.isFinite(candidate.__npVersion) &&\n \"__npSettings\" in candidate\n );\n}\n\n/**\n * Run the plugin's `configMigrate` from `from` to current schema version.\n * No-op when versions match or the plugin doesn't declare a migrator.\n * Defensive try/catch — a buggy migrate fn shouldn't blow up the read\n * path; we fall back to the original value and let `safeParse` decide.\n *\n * Mirrors `applyMigration` in `packages/core/src/themes/settings.ts` line\n * for line.\n */\nexport function applyPluginConfigMigration(\n registration: {\n configVersion?: number;\n configMigrate?: (old: unknown, fromVersion: number) => unknown;\n },\n rawValue: unknown,\n fromVersion: number,\n): unknown {\n const target = registration.configVersion ?? 1;\n if (fromVersion >= target) return rawValue;\n const migrate = registration.configMigrate;\n if (typeof migrate !== \"function\") return rawValue;\n try {\n return migrate(rawValue, fromVersion);\n } catch {\n return rawValue;\n }\n}\n\nfunction defaultsFrom(fields: NpThemeSettingsField[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.default !== undefined) {\n out[f.name] = f.default;\n continue;\n }\n if (f.type === \"object\") {\n out[f.name] = defaultsFrom(f.fields);\n }\n if (f.type === \"array\") {\n out[f.name] = [];\n }\n }\n return out;\n}\n\nexport interface NpPluginConfigResult {\n pluginId: string;\n /** Parsed config or schema defaults. Empty object when the plugin has\n * no configSchema. */\n value: unknown;\n /** True when there's a stored row, regardless of whether it passed\n * validation. */\n hasPersisted: boolean;\n /** Set when the persisted value failed `schema.parse()`. The admin\n * surface uses this to render a \"settings were reset\" banner. */\n parseError?: string;\n}\n\n/**\n * Read the persisted config for a plugin and parse it via the plugin's\n * `configSchema`. Returns the parsed value when valid; falls back to\n * schema defaults on parse failure (with the failure recorded for the\n * admin to surface, see `getPluginConfigWithStatus`).\n *\n * Return type is `unknown` because core can't type-narrow to the plugin's\n * `z.infer<typeof configSchema>` — the schema lives in the plugin\n * package, not in core. Plugin code that reads its own config should\n * cast at the call site, ideally against an exported type alias from the\n * plugin package itself:\n *\n * // packages/plugins/oauth-github/src/index.ts\n * export const configSchema = z.object({ ... });\n * export type GithubOauthConfig = z.infer<typeof configSchema>;\n *\n * // a plugin handler\n * const config = (await getPluginConfig(\"oauth-github\")) as GithubOauthConfig;\n */\nexport async function getPluginConfig(pluginId: string): Promise<unknown> {\n const result = await getPluginConfigWithStatus(pluginId);\n return result.value;\n}\n\nexport async function getPluginConfigWithStatus(\n pluginId: string,\n): Promise<NpPluginConfigResult> {\n // Registration is consulted for schema-driven validation + defaults\n // when present, but a missing registration MUST NOT short-circuit the\n // DB read. `ctx.settings.setPlugin` writes to `np_settings` for any\n // pluginId regardless of registration — bailing here would create a\n // read/write asymmetry where stored config silently disappears on\n // read. Treat \"not registered\" the same as \"registered with no\n // schema\": surface the row raw if it exists.\n const registration = getPluginRegistration(pluginId);\n const schema = registration?.configSchema as ZodTypeAny | undefined;\n\n let row: { value: unknown } | undefined;\n try {\n const db = getDb();\n const siteId = (await getCurrentSiteId()) ?? DEFAULT_SITE;\n const rows = (await db\n .select()\n .from(npSettings)\n .where(\n and(eq(npSettings.siteId, siteId), eq(npSettings.key, configKey(pluginId))),\n )\n .limit(1)) as Array<{ value: unknown }>;\n row = rows[0];\n } catch {\n // DB not ready — caller is asking before bootstrap. Return empty\n // shape; treats DB-not-ready the same as \"no row stored yet\".\n return { pluginId, value: schema ? defaultsFromSchema(schema) : {}, hasPersisted: false };\n }\n\n if (!schema) {\n // Plugin doesn't declare a configSchema. If a row exists (legacy\n // hand-coded UI saved into np_settings, or migrated from\n // np_plugins.config), surface it raw — callers can still read it.\n if (!row) {\n return { pluginId, value: {}, hasPersisted: false };\n }\n const versioned = isVersionedPluginConfig(row.value) ? row.value : null;\n const rawValue = versioned ? versioned.__npSettings : row.value;\n return {\n pluginId,\n value: rawValue ?? {},\n hasPersisted: true,\n };\n }\n\n const fields = introspectThemeSettingsSchema(schema);\n const defaults = defaultsFrom(fields);\n\n if (!row) {\n const parsed = schema.safeParse(defaults);\n return {\n pluginId,\n value: parsed.success ? parsed.data : defaults,\n hasPersisted: false,\n };\n }\n\n // Versioned envelope detection + lazy migration. Mirrors\n // `getThemeSettingsWithStatus` exactly. Registration is guaranteed\n // defined here: schema is only truthy when registration exists\n // (line ~152), and the `if (!schema) return` above narrows the rest\n // of the function — but TS can't infer that across `?.` so we\n // restate it for the migration helper.\n const versioned = isVersionedPluginConfig(row.value) ? row.value : null;\n const storedVersion = versioned ? versioned.__npVersion : 1;\n const rawValue = versioned ? versioned.__npSettings : row.value;\n const valueToParse = applyPluginConfigMigration(\n registration ?? { configVersion: 1 },\n rawValue,\n storedVersion,\n );\n\n const parsed = schema.safeParse(valueToParse);\n if (parsed.success) {\n return { pluginId, value: parsed.data, hasPersisted: true };\n }\n\n return {\n pluginId,\n value: defaults,\n hasPersisted: true,\n parseError: parsed.error.message,\n };\n}\n\nfunction defaultsFromSchema(schema: ZodTypeAny): Record<string, unknown> {\n return defaultsFrom(introspectThemeSettingsSchema(schema));\n}\n\n/**\n * Validate and persist a plugin's config. Throws `NpValidationError` when\n * `value` doesn't pass the schema — the admin form must surface\n * field-level errors before calling this.\n *\n * **Cache invalidation is the caller's responsibility.** This function\n * writes to `np_settings` only; it doesn't import `next/cache`. The\n * admin API route (`PUT /api/admin/plugins/[id]/config`) busts\n * `np:plugin:<id>` after a successful write.\n *\n * Mirrors `setThemeSettings` in `packages/core/src/themes/settings.ts`.\n */\nexport async function setPluginConfig(\n pluginId: string,\n value: unknown,\n updatedBy: string | null = null,\n): Promise<unknown> {\n const registration = getPluginRegistration(pluginId);\n if (!registration) {\n throw new NpValidationError(\"Invalid input\", [\n {\n field: \"pluginId\",\n message: `Unknown plugin '${pluginId}'. Register it in nexpress.config.ts first.`,\n },\n ]);\n }\n const schema = registration.configSchema as ZodTypeAny | undefined;\n if (!schema) {\n throw new NpValidationError(\"Invalid input\", [\n {\n field: \"pluginId\",\n message: `Plugin '${pluginId}' does not declare a configSchema.`,\n },\n ]);\n }\n\n const parsed = schema.safeParse(value);\n if (!parsed.success) {\n throw new NpValidationError(\n \"Config failed validation\",\n parsed.error.issues.map((i) => ({\n field: i.path.join(\".\"),\n message: i.message,\n })),\n );\n }\n\n const wrapped: NpVersionedPluginConfig = {\n __npVersion: registration.configVersion ?? 1,\n __npSettings: parsed.data,\n };\n\n const db = getDb();\n const now = new Date();\n const siteId = (await getCurrentSiteId()) ?? DEFAULT_SITE;\n await db\n .insert(npSettings)\n .values({\n siteId,\n key: configKey(pluginId),\n value: wrapped,\n updatedAt: now,\n updatedBy,\n })\n .onConflictDoUpdate({\n target: [npSettings.siteId, npSettings.key],\n set: { value: wrapped, updatedAt: now, updatedBy },\n });\n\n return parsed.data;\n}\n\n/** Cache tag for a plugin's config invalidation. Per the prefix policy\n * in CLAUDE.md (Naming convention table) every framework-owned tag\n * uses the `np` prefix. Distinct from the legacy `nx:theme:<siteId>`\n * tag — see `docs/design/plugin-config-auto-form.md` § 7. */\nexport function pluginConfigCacheTag(pluginId: string): string {\n return `np:plugin:${pluginId}`;\n}\n","import type { ZodTypeAny } from \"zod\";\n\n/**\n * Phase F.3 — server-side introspection of a theme's\n * `settingsSchema` Zod tree into a JSON metadata shape the\n * admin form generator consumes.\n *\n * The schema lives in the theme package (server bundle); we\n * don't ship the schema itself to the browser. Instead, this\n * function walks the tree once on the server, emits the\n * metadata as plain JSON, and the admin renders form fields\n * from the metadata. The browser doesn't need zod at runtime.\n *\n * Coverage in v0.2: text, url, color (regex heuristic), number,\n * boolean, enum, array(object), object. Anything else\n * introspects as `{ type: \"unsupported\" }` so the form generator\n * can render a JSON textarea fallback (operator can still edit;\n * a follow-up phase widens coverage).\n */\n\nexport type NpThemeSettingsField =\n | NpThemeSettingsTextField\n | NpThemeSettingsTextareaField\n | NpThemeSettingsPasswordField\n | NpThemeSettingsUrlField\n | NpThemeSettingsColorField\n | NpThemeSettingsNumberField\n | NpThemeSettingsBooleanField\n | NpThemeSettingsEnumField\n | NpThemeSettingsArrayField\n | NpThemeSettingsStringArrayField\n | NpThemeSettingsObjectField\n | NpThemeSettingsUnsupportedField;\n\ninterface NpThemeSettingsFieldBase {\n /** Field path key (\"hero\", \"social.0.url\", etc. — the\n * introspector returns flat keys per node; nested objects\n * carry their own children). */\n name: string;\n label?: string;\n description?: string;\n required: boolean;\n default?: unknown;\n}\n\nexport interface NpThemeSettingsTextField extends NpThemeSettingsFieldBase {\n type: \"text\";\n}\n\nexport interface NpThemeSettingsTextareaField extends NpThemeSettingsFieldBase {\n type: \"textarea\";\n /** Optional row count hint for the rendered `<textarea>`.\n * Theme authors set this via `.meta({ widget: \"textarea\",\n * rows: 6 })`. Defaults to 4 when unset. */\n rows?: number;\n}\n\nexport interface NpThemeSettingsPasswordField extends NpThemeSettingsFieldBase {\n type: \"password\";\n}\n\nexport interface NpThemeSettingsUrlField extends NpThemeSettingsFieldBase {\n type: \"url\";\n}\n\nexport interface NpThemeSettingsColorField extends NpThemeSettingsFieldBase {\n type: \"color\";\n}\n\nexport interface NpThemeSettingsNumberField extends NpThemeSettingsFieldBase {\n type: \"number\";\n int?: boolean;\n min?: number;\n max?: number;\n}\n\nexport interface NpThemeSettingsBooleanField extends NpThemeSettingsFieldBase {\n type: \"boolean\";\n}\n\nexport interface NpThemeSettingsEnumField extends NpThemeSettingsFieldBase {\n type: \"enum\";\n options: string[];\n}\n\nexport interface NpThemeSettingsArrayField extends NpThemeSettingsFieldBase {\n type: \"array\";\n /** v0.2 supports `z.array(z.object(...))`. The element\n * schema introspects as the array's child fields. */\n element: NpThemeSettingsField[];\n}\n\n/** Phase G follow-up — `z.array(z.string())`. Renders as a\n * one-item-per-line input. Surfaced for OAuth scopes and\n * similar string-list configs that don't fit the object-array\n * shape; previously fell through to the JSON-textarea\n * `unsupported` fallback. */\nexport interface NpThemeSettingsStringArrayField extends NpThemeSettingsFieldBase {\n type: \"string-array\";\n}\n\nexport interface NpThemeSettingsObjectField extends NpThemeSettingsFieldBase {\n type: \"object\";\n fields: NpThemeSettingsField[];\n}\n\nexport interface NpThemeSettingsUnsupportedField extends NpThemeSettingsFieldBase {\n type: \"unsupported\";\n /** Best-effort label for what was at this position so\n * operators can recognize their schema in the JSON fallback. */\n zodTypeName: string;\n}\n\n// Heuristic: regex sources that look like a hex color check.\n// We test against the regex `source` string (no flags, no\n// surrounding slashes), so e.g. `/^#[0-9a-f]{6}$/i` arrives\n// as `^#[0-9a-f]{6}$`. Matches both 6-digit and 3-to-8 digit\n// variants, case sensitivity-agnostic via the `i` flag on\n// the heuristic itself.\nconst COLOR_REGEX_PATTERNS = [\n /^\\^#\\[0-9a-f\\]\\{6\\}\\$$/i,\n /^\\^#\\[0-9a-f\\]\\{3,8\\}\\$$/i,\n /^\\^#\\[\\\\da-f\\]\\{6\\}\\$$/i,\n];\n\ninterface ZodCheck {\n _zod?: { def?: { format?: string; pattern?: { source: string }; check?: string; value?: number } };\n}\n\ninterface ZodDef {\n type: string;\n innerType?: { _def: ZodDef };\n defaultValue?: unknown;\n description?: string;\n shape?: Record<string, { _def: ZodDef; description?: string }>;\n entries?: Record<string, string>;\n element?: { _def: ZodDef };\n checks?: ZodCheck[];\n}\n\ninterface ZodNode {\n _def: ZodDef;\n description?: string;\n shape?: Record<string, ZodNode>;\n}\n\n/**\n * Strip `default` / `optional` / `nullable` wrappers, returning\n * the inner schema, the resolved default value, and whether\n * the field is required (i.e. neither optional nor nullable).\n */\nfunction unwrap(node: ZodNode): {\n inner: ZodNode;\n defaultValue: unknown;\n required: boolean;\n} {\n let current = node;\n let defaultValue: unknown = undefined;\n let required = true;\n\n while (true) {\n const t = current._def.type;\n if (t === \"default\") {\n defaultValue =\n typeof current._def.defaultValue === \"function\"\n ? (current._def.defaultValue as () => unknown)()\n : current._def.defaultValue;\n current = (current._def.innerType as ZodNode | undefined) ?? current;\n if (!current._def.innerType) break;\n continue;\n }\n if (t === \"optional\" || t === \"nullable\") {\n required = false;\n const next = current._def.innerType as ZodNode | undefined;\n if (!next) break;\n current = next;\n continue;\n }\n break;\n }\n\n return { inner: current, defaultValue, required };\n}\n\nfunction detectStringFormat(\n checks: ZodCheck[] | undefined,\n): \"url\" | \"color\" | \"text\" {\n if (!checks) return \"text\";\n for (const c of checks) {\n const fmt = c._zod?.def?.format;\n if (fmt === \"url\") return \"url\";\n if (fmt === \"regex\") {\n const src = c._zod?.def?.pattern?.source;\n if (src && COLOR_REGEX_PATTERNS.some((p) => p.test(src))) {\n return \"color\";\n }\n }\n }\n return \"text\";\n}\n\n/**\n * Phase F.3 follow-up — pull `.meta()` off a Zod node when\n * present. Used to read theme-author hints like\n * `{ widget: \"textarea\", rows: 6 }` that don't fit Zod's\n * narrow widget matrix (z.string() has no textarea variant\n * built in).\n */\nfunction readMeta(node: ZodNode): Record<string, unknown> | undefined {\n const fn = (node as unknown as { meta?: () => unknown }).meta;\n if (typeof fn !== \"function\") return undefined;\n const out = fn.call(node);\n return out && typeof out === \"object\" ? (out as Record<string, unknown>) : undefined;\n}\n\nfunction detectNumberConstraints(\n checks: ZodCheck[] | undefined,\n): { int?: boolean; min?: number; max?: number } {\n const out: { int?: boolean; min?: number; max?: number } = {};\n if (!checks) return out;\n for (const c of checks) {\n const def = c._zod?.def;\n if (!def) continue;\n if (def.format === \"safeint\" || def.check === \"int\") out.int = true;\n if (def.check === \"greater_than\" && typeof def.value === \"number\")\n out.min = def.value;\n if (def.check === \"less_than\" && typeof def.value === \"number\")\n out.max = def.value;\n }\n return out;\n}\n\nfunction introspectField(\n name: string,\n node: ZodNode,\n): NpThemeSettingsField {\n const description = node.description;\n const { inner, defaultValue, required } = unwrap(node);\n const innerDef = inner._def;\n const base: NpThemeSettingsFieldBase = {\n name,\n description,\n label: description,\n required,\n default: defaultValue,\n };\n\n switch (innerDef.type) {\n case \"string\": {\n // Phase F.3 follow-up — `.meta({ widget: \"textarea\" })`\n // opts a `z.string()` into multi-line rendering. Theme\n // authors pair it with `.describe()` for the field\n // label; row count is optional (defaults to 4).\n //\n // Check `node` (outer) first then `inner` because Zod v4's\n // `.meta()` returns a new instance, so the meta lives at\n // whichever level the author called .meta() at:\n //\n // z.string().meta({...}).optional() → meta on inner string\n // z.string().optional().meta({...}) → meta on outer optional\n //\n // Both patterns are valid in author code; both should work.\n const meta = readMeta(node) ?? readMeta(inner);\n if (meta && meta.sensitive === true) {\n return { ...base, type: \"password\" };\n }\n if (meta && meta.widget === \"textarea\") {\n const rows =\n typeof meta.rows === \"number\" && meta.rows > 0\n ? meta.rows\n : undefined;\n return {\n ...base,\n type: \"textarea\",\n ...(rows !== undefined ? { rows } : {}),\n };\n }\n const fmt = detectStringFormat(innerDef.checks);\n return { ...base, type: fmt };\n }\n case \"number\": {\n const c = detectNumberConstraints(innerDef.checks);\n return { ...base, type: \"number\", ...c };\n }\n case \"boolean\":\n return { ...base, type: \"boolean\" };\n case \"enum\": {\n const entries = innerDef.entries ?? {};\n return { ...base, type: \"enum\", options: Object.values(entries) };\n }\n case \"array\": {\n const element = innerDef.element as ZodNode | undefined;\n // v0.2 supports z.array(z.object(...)) — typed nested form\n // for each item.\n if (element?._def.type === \"object\" && element._def.shape) {\n const childFields = introspectShape(element._def.shape);\n return { ...base, type: \"array\", element: childFields };\n }\n // Phase G follow-up — z.array(z.string()) gets a dedicated\n // string-array widget (one item per line). Surfaced for\n // OAuth scopes and similar string-list configs.\n if (element?._def.type === \"string\") {\n return { ...base, type: \"string-array\" };\n }\n return { ...base, type: \"unsupported\", zodTypeName: \"array\" };\n }\n case \"object\": {\n const shape = innerDef.shape;\n if (shape) {\n return { ...base, type: \"object\", fields: introspectShape(shape) };\n }\n return { ...base, type: \"unsupported\", zodTypeName: \"object\" };\n }\n default:\n return {\n ...base,\n type: \"unsupported\",\n zodTypeName: innerDef.type ?? \"unknown\",\n };\n }\n}\n\nfunction introspectShape(\n shape: Record<string, { _def: ZodDef; description?: string }>,\n): NpThemeSettingsField[] {\n const out: NpThemeSettingsField[] = [];\n for (const [name, raw] of Object.entries(shape)) {\n out.push(introspectField(name, raw as ZodNode));\n }\n return out;\n}\n\n/**\n * Walk a theme's `settingsSchema` (top-level z.object) and emit\n * the form metadata. Returns an empty array when the schema\n * isn't a top-level object — themes are expected to ship\n * `settingsSchema: z.object({...})` (validated implicitly: a\n * non-object top schema yields an empty form, signalling\n * \"nothing to configure\").\n */\nexport function introspectThemeSettingsSchema(\n schema: ZodTypeAny | undefined,\n): NpThemeSettingsField[] {\n if (!schema) return [];\n // Strip any top-level default/optional/nullable wrapper before\n // checking for object shape — themes that wrap their whole\n // schema in `.default({...})` are unusual but valid; without\n // unwrap we'd silently render an empty form.\n const { inner } = unwrap(schema as unknown as ZodNode);\n if (inner._def.type !== \"object\" || !inner._def.shape) return [];\n return introspectShape(inner._def.shape);\n}\n"],"mappings":"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","names":["versioned","rawValue","parsed"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugins/config.ts","../src/themes/settings-schema.ts"],"sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport type { ZodTypeAny } from \"zod\";\n\nimport { getDb } from \"../db/index.js\";\nimport { npSettings } from \"../db/schema/system.js\";\nimport { NpValidationError } from \"../errors.js\";\nimport { getCurrentSiteId } from \"../sites/context.js\";\nimport { getPluginRegistration } from \"./host.js\";\nimport {\n introspectThemeSettingsSchema,\n type NpThemeSettingsField,\n} from \"../themes/settings-schema.js\";\n\nconst DEFAULT_SITE = \"default\";\nconst CONFIG_KEY_PREFIX = \"plugin.config:\";\n\n/**\n * G.1 — per-plugin operator config.\n *\n * Stored at `np_settings.(site_id, key=\"plugin.config:<pluginId>\")`.\n * Mirrors theme settings storage exactly, including the `__npVersion` /\n * `__npSettings` envelope, so a future shared `getCachedSetting<T>(key)`\n * helper can read both surfaces. Cache invalidation rides a new\n * `np:plugin:<id>` tag (see `packages/next/src/cache.ts`).\n *\n * Per locked decision E (`docs/design/plugin-config-auto-form.md` § 2):\n * we store under `np_settings`, NOT `np_plugins.config` (the legacy\n * column was dropped in the same migration that introduced this module).\n */\n\nfunction configKey(pluginId: string): string {\n return `${CONFIG_KEY_PREFIX}${pluginId}`;\n}\n\n/**\n * Versioned envelope shape for persisted plugin config — identical to the\n * theme `NpVersionedSettings` shape. Two parallel definitions instead of a\n * shared one because (a) themes and plugins share zero schema surface\n * otherwise, (b) the type is only ~5 lines, and (c) collapsing them would\n * couple `themes/` and `plugins/` modules without functional benefit.\n */\nexport interface NpVersionedPluginConfig {\n __npVersion: number;\n __npSettings: unknown;\n}\n\nexport function isVersionedPluginConfig(\n value: unknown,\n): value is NpVersionedPluginConfig {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Partial<NpVersionedPluginConfig>;\n return (\n typeof candidate.__npVersion === \"number\" &&\n Number.isFinite(candidate.__npVersion) &&\n \"__npSettings\" in candidate\n );\n}\n\n/**\n * Run the plugin's `configMigrate` from `from` to current schema version.\n * No-op when versions match or the plugin doesn't declare a migrator.\n * Defensive try/catch — a buggy migrate fn shouldn't blow up the read\n * path; we fall back to the original value and let `safeParse` decide.\n *\n * Mirrors `applyMigration` in `packages/core/src/themes/settings.ts` line\n * for line.\n */\nexport function applyPluginConfigMigration(\n registration: {\n configVersion?: number;\n configMigrate?: (old: unknown, fromVersion: number) => unknown;\n },\n rawValue: unknown,\n fromVersion: number,\n): unknown {\n const target = registration.configVersion ?? 1;\n if (fromVersion >= target) return rawValue;\n const migrate = registration.configMigrate;\n if (typeof migrate !== \"function\") return rawValue;\n try {\n return migrate(rawValue, fromVersion);\n } catch {\n return rawValue;\n }\n}\n\nfunction defaultsFrom(fields: NpThemeSettingsField[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.default !== undefined) {\n out[f.name] = f.default;\n continue;\n }\n if (f.type === \"object\") {\n out[f.name] = defaultsFrom(f.fields);\n }\n if (f.type === \"array\") {\n out[f.name] = [];\n }\n }\n return out;\n}\n\nexport interface NpPluginConfigResult {\n pluginId: string;\n /** Parsed config or schema defaults. Empty object when the plugin has\n * no configSchema. */\n value: unknown;\n /** True when there's a stored row, regardless of whether it passed\n * validation. */\n hasPersisted: boolean;\n /** Set when the persisted value failed `schema.parse()`. The admin\n * surface uses this to render a \"settings were reset\" banner. */\n parseError?: string;\n}\n\n/**\n * Read the persisted config for a plugin and parse it via the plugin's\n * `configSchema`. Returns the parsed value when valid; falls back to\n * schema defaults on parse failure (with the failure recorded for the\n * admin to surface, see `getPluginConfigWithStatus`).\n *\n * Return type is `unknown` because core can't type-narrow to the plugin's\n * `z.infer<typeof configSchema>` — the schema lives in the plugin\n * package, not in core. Plugin code that reads its own config should\n * cast at the call site, ideally against an exported type alias from the\n * plugin package itself:\n *\n * // packages/plugins/oauth-github/src/index.ts\n * export const configSchema = z.object({ ... });\n * export type GithubOauthConfig = z.infer<typeof configSchema>;\n *\n * // a plugin handler\n * const config = (await getPluginConfig(\"oauth-github\")) as GithubOauthConfig;\n */\nexport async function getPluginConfig(pluginId: string): Promise<unknown> {\n const result = await getPluginConfigWithStatus(pluginId);\n return result.value;\n}\n\nexport async function getPluginConfigWithStatus(\n pluginId: string,\n): Promise<NpPluginConfigResult> {\n // Registration is consulted for schema-driven validation + defaults\n // when present, but a missing registration MUST NOT short-circuit the\n // DB read. `ctx.settings.setPlugin` writes to `np_settings` for any\n // pluginId regardless of registration — bailing here would create a\n // read/write asymmetry where stored config silently disappears on\n // read. Treat \"not registered\" the same as \"registered with no\n // schema\": surface the row raw if it exists.\n const registration = getPluginRegistration(pluginId);\n const schema = registration?.configSchema as ZodTypeAny | undefined;\n\n let row: { value: unknown } | undefined;\n try {\n const db = getDb();\n const siteId = (await getCurrentSiteId()) ?? DEFAULT_SITE;\n const rows = (await db\n .select()\n .from(npSettings)\n .where(\n and(eq(npSettings.siteId, siteId), eq(npSettings.key, configKey(pluginId))),\n )\n .limit(1)) as Array<{ value: unknown }>;\n row = rows[0];\n } catch {\n // DB not ready — caller is asking before bootstrap. Return empty\n // shape; treats DB-not-ready the same as \"no row stored yet\".\n return { pluginId, value: schema ? defaultsFromSchema(schema) : {}, hasPersisted: false };\n }\n\n if (!schema) {\n // Plugin doesn't declare a configSchema. If a row exists (legacy\n // hand-coded UI saved into np_settings, or migrated from\n // np_plugins.config), surface it raw — callers can still read it.\n if (!row) {\n return { pluginId, value: {}, hasPersisted: false };\n }\n const versioned = isVersionedPluginConfig(row.value) ? row.value : null;\n const rawValue = versioned ? versioned.__npSettings : row.value;\n return {\n pluginId,\n value: rawValue ?? {},\n hasPersisted: true,\n };\n }\n\n const fields = introspectThemeSettingsSchema(schema);\n const defaults = defaultsFrom(fields);\n\n if (!row) {\n const parsed = schema.safeParse(defaults);\n return {\n pluginId,\n value: parsed.success ? parsed.data : defaults,\n hasPersisted: false,\n };\n }\n\n // Versioned envelope detection + lazy migration. Mirrors\n // `getThemeSettingsWithStatus` exactly. Registration is guaranteed\n // defined here: schema is only truthy when registration exists\n // (line ~152), and the `if (!schema) return` above narrows the rest\n // of the function — but TS can't infer that across `?.` so we\n // restate it for the migration helper.\n const versioned = isVersionedPluginConfig(row.value) ? row.value : null;\n const storedVersion = versioned ? versioned.__npVersion : 1;\n const rawValue = versioned ? versioned.__npSettings : row.value;\n const valueToParse = applyPluginConfigMigration(\n registration ?? { configVersion: 1 },\n rawValue,\n storedVersion,\n );\n\n const parsed = schema.safeParse(valueToParse);\n if (parsed.success) {\n return { pluginId, value: parsed.data, hasPersisted: true };\n }\n\n return {\n pluginId,\n value: defaults,\n hasPersisted: true,\n parseError: parsed.error.message,\n };\n}\n\nfunction defaultsFromSchema(schema: ZodTypeAny): Record<string, unknown> {\n return defaultsFrom(introspectThemeSettingsSchema(schema));\n}\n\n/**\n * Validate and persist a plugin's config. Throws `NpValidationError` when\n * `value` doesn't pass the schema — the admin form must surface\n * field-level errors before calling this.\n *\n * **Cache invalidation is the caller's responsibility.** This function\n * writes to `np_settings` only; it doesn't import `next/cache`. The\n * admin API route (`PUT /api/admin/plugins/[id]/config`) busts\n * `np:plugin:<id>` after a successful write.\n *\n * Mirrors `setThemeSettings` in `packages/core/src/themes/settings.ts`.\n */\nexport async function setPluginConfig(\n pluginId: string,\n value: unknown,\n updatedBy: string | null = null,\n): Promise<unknown> {\n const registration = getPluginRegistration(pluginId);\n if (!registration) {\n throw new NpValidationError(\"Invalid input\", [\n {\n field: \"pluginId\",\n message: `Unknown plugin '${pluginId}'. Register it in nexpress.config.ts first.`,\n },\n ]);\n }\n const schema = registration.configSchema as ZodTypeAny | undefined;\n if (!schema) {\n throw new NpValidationError(\"Invalid input\", [\n {\n field: \"pluginId\",\n message: `Plugin '${pluginId}' does not declare a configSchema.`,\n },\n ]);\n }\n\n const parsed = schema.safeParse(value);\n if (!parsed.success) {\n throw new NpValidationError(\n \"Config failed validation\",\n parsed.error.issues.map((i) => ({\n field: i.path.join(\".\"),\n message: i.message,\n })),\n );\n }\n\n const wrapped: NpVersionedPluginConfig = {\n __npVersion: registration.configVersion ?? 1,\n __npSettings: parsed.data,\n };\n\n const db = getDb();\n const now = new Date();\n const siteId = (await getCurrentSiteId()) ?? DEFAULT_SITE;\n await db\n .insert(npSettings)\n .values({\n siteId,\n key: configKey(pluginId),\n value: wrapped,\n updatedAt: now,\n updatedBy,\n })\n .onConflictDoUpdate({\n target: [npSettings.siteId, npSettings.key],\n set: { value: wrapped, updatedAt: now, updatedBy },\n });\n\n return parsed.data;\n}\n\n/** Cache tag for a plugin's config invalidation. Per the prefix policy\n * in CLAUDE.md (Naming convention table) every framework-owned tag\n * uses the `np` prefix. Distinct from the legacy `nx:theme:<siteId>`\n * tag — see `docs/design/plugin-config-auto-form.md` § 7. */\nexport function pluginConfigCacheTag(pluginId: string): string {\n return `np:plugin:${pluginId}`;\n}\n","import type { ZodTypeAny } from \"zod\";\n\n/**\n * Phase F.3 — server-side introspection of a theme's\n * `settingsSchema` Zod tree into a JSON metadata shape the\n * admin form generator consumes.\n *\n * The schema lives in the theme package (server bundle); we\n * don't ship the schema itself to the browser. Instead, this\n * function walks the tree once on the server, emits the\n * metadata as plain JSON, and the admin renders form fields\n * from the metadata. The browser doesn't need zod at runtime.\n *\n * Coverage in v0.2: text, url, color (regex heuristic), number,\n * boolean, enum, array(object), object. Anything else\n * introspects as `{ type: \"unsupported\" }` so the form generator\n * can render a JSON textarea fallback (operator can still edit;\n * a follow-up phase widens coverage).\n */\n\nexport type NpThemeSettingsField =\n | NpThemeSettingsTextField\n | NpThemeSettingsTextareaField\n | NpThemeSettingsPasswordField\n | NpThemeSettingsUrlField\n | NpThemeSettingsColorField\n | NpThemeSettingsNumberField\n | NpThemeSettingsBooleanField\n | NpThemeSettingsEnumField\n | NpThemeSettingsArrayField\n | NpThemeSettingsStringArrayField\n | NpThemeSettingsObjectField\n | NpThemeSettingsUnsupportedField;\n\ninterface NpThemeSettingsFieldBase {\n /** Field path key (\"hero\", \"social.0.url\", etc. — the\n * introspector returns flat keys per node; nested objects\n * carry their own children). */\n name: string;\n label?: string;\n description?: string;\n required: boolean;\n default?: unknown;\n}\n\nexport interface NpThemeSettingsTextField extends NpThemeSettingsFieldBase {\n type: \"text\";\n}\n\nexport interface NpThemeSettingsTextareaField extends NpThemeSettingsFieldBase {\n type: \"textarea\";\n /** Optional row count hint for the rendered `<textarea>`.\n * Theme authors set this via `.meta({ widget: \"textarea\",\n * rows: 6 })`. Defaults to 4 when unset. */\n rows?: number;\n}\n\nexport interface NpThemeSettingsPasswordField extends NpThemeSettingsFieldBase {\n type: \"password\";\n}\n\nexport interface NpThemeSettingsUrlField extends NpThemeSettingsFieldBase {\n type: \"url\";\n}\n\nexport interface NpThemeSettingsColorField extends NpThemeSettingsFieldBase {\n type: \"color\";\n}\n\nexport interface NpThemeSettingsNumberField extends NpThemeSettingsFieldBase {\n type: \"number\";\n int?: boolean;\n min?: number;\n max?: number;\n}\n\nexport interface NpThemeSettingsBooleanField extends NpThemeSettingsFieldBase {\n type: \"boolean\";\n}\n\nexport interface NpThemeSettingsEnumField extends NpThemeSettingsFieldBase {\n type: \"enum\";\n options: string[];\n}\n\nexport interface NpThemeSettingsArrayField extends NpThemeSettingsFieldBase {\n type: \"array\";\n /** v0.2 supports `z.array(z.object(...))`. The element\n * schema introspects as the array's child fields. */\n element: NpThemeSettingsField[];\n}\n\n/** Phase G follow-up — `z.array(z.string())`. Renders as a\n * one-item-per-line input. Surfaced for OAuth scopes and\n * similar string-list configs that don't fit the object-array\n * shape; previously fell through to the JSON-textarea\n * `unsupported` fallback. */\nexport interface NpThemeSettingsStringArrayField extends NpThemeSettingsFieldBase {\n type: \"string-array\";\n}\n\nexport interface NpThemeSettingsObjectField extends NpThemeSettingsFieldBase {\n type: \"object\";\n fields: NpThemeSettingsField[];\n}\n\nexport interface NpThemeSettingsUnsupportedField extends NpThemeSettingsFieldBase {\n type: \"unsupported\";\n /** Best-effort label for what was at this position so\n * operators can recognize their schema in the JSON fallback. */\n zodTypeName: string;\n}\n\n// Heuristic: regex sources that look like a hex color check.\n// We test against the regex `source` string (no flags, no\n// surrounding slashes), so e.g. `/^#[0-9a-f]{6}$/i` arrives\n// as `^#[0-9a-f]{6}$`. Matches both 6-digit and 3-to-8 digit\n// variants, case sensitivity-agnostic via the `i` flag on\n// the heuristic itself.\nconst COLOR_REGEX_PATTERNS = [\n /^\\^#\\[0-9a-f\\]\\{6\\}\\$$/i,\n /^\\^#\\[0-9a-f\\]\\{3,8\\}\\$$/i,\n /^\\^#\\[\\\\da-f\\]\\{6\\}\\$$/i,\n];\n\ninterface ZodCheck {\n _zod?: { def?: { format?: string; pattern?: { source: string }; check?: string; value?: number } };\n}\n\ninterface ZodDef {\n type: string;\n innerType?: { _def: ZodDef };\n defaultValue?: unknown;\n description?: string;\n shape?: Record<string, { _def: ZodDef; description?: string }>;\n entries?: Record<string, string>;\n element?: { _def: ZodDef };\n checks?: ZodCheck[];\n}\n\ninterface ZodNode {\n _def: ZodDef;\n description?: string;\n shape?: Record<string, ZodNode>;\n}\n\n/**\n * Strip `default` / `optional` / `nullable` wrappers, returning\n * the inner schema, the resolved default value, and whether\n * the field is required (i.e. neither optional nor nullable).\n */\nfunction unwrap(node: ZodNode): {\n inner: ZodNode;\n defaultValue: unknown;\n required: boolean;\n} {\n let current = node;\n let defaultValue: unknown = undefined;\n let required = true;\n\n while (true) {\n const t = current._def.type;\n if (t === \"default\") {\n defaultValue =\n typeof current._def.defaultValue === \"function\"\n ? (current._def.defaultValue as () => unknown)()\n : current._def.defaultValue;\n current = (current._def.innerType) ?? current;\n if (!current._def.innerType) break;\n continue;\n }\n if (t === \"optional\" || t === \"nullable\") {\n required = false;\n const next = current._def.innerType;\n if (!next) break;\n current = next;\n continue;\n }\n break;\n }\n\n return { inner: current, defaultValue, required };\n}\n\nfunction detectStringFormat(\n checks: ZodCheck[] | undefined,\n): \"url\" | \"color\" | \"text\" {\n if (!checks) return \"text\";\n for (const c of checks) {\n const fmt = c._zod?.def?.format;\n if (fmt === \"url\") return \"url\";\n if (fmt === \"regex\") {\n const src = c._zod?.def?.pattern?.source;\n if (src && COLOR_REGEX_PATTERNS.some((p) => p.test(src))) {\n return \"color\";\n }\n }\n }\n return \"text\";\n}\n\n/**\n * Phase F.3 follow-up — pull `.meta()` off a Zod node when\n * present. Used to read theme-author hints like\n * `{ widget: \"textarea\", rows: 6 }` that don't fit Zod's\n * narrow widget matrix (z.string() has no textarea variant\n * built in).\n */\nfunction readMeta(node: ZodNode): Record<string, unknown> | undefined {\n const fn = (node as unknown as { meta?: () => unknown }).meta;\n if (typeof fn !== \"function\") return undefined;\n const out = fn.call(node);\n return out && typeof out === \"object\" ? (out as Record<string, unknown>) : undefined;\n}\n\nfunction detectNumberConstraints(\n checks: ZodCheck[] | undefined,\n): { int?: boolean; min?: number; max?: number } {\n const out: { int?: boolean; min?: number; max?: number } = {};\n if (!checks) return out;\n for (const c of checks) {\n const def = c._zod?.def;\n if (!def) continue;\n if (def.format === \"safeint\" || def.check === \"int\") out.int = true;\n if (def.check === \"greater_than\" && typeof def.value === \"number\")\n out.min = def.value;\n if (def.check === \"less_than\" && typeof def.value === \"number\")\n out.max = def.value;\n }\n return out;\n}\n\nfunction introspectField(\n name: string,\n node: ZodNode,\n): NpThemeSettingsField {\n const description = node.description;\n const { inner, defaultValue, required } = unwrap(node);\n const innerDef = inner._def;\n const base: NpThemeSettingsFieldBase = {\n name,\n description,\n label: description,\n required,\n default: defaultValue,\n };\n\n switch (innerDef.type) {\n case \"string\": {\n // Phase F.3 follow-up — `.meta({ widget: \"textarea\" })`\n // opts a `z.string()` into multi-line rendering. Theme\n // authors pair it with `.describe()` for the field\n // label; row count is optional (defaults to 4).\n //\n // Check `node` (outer) first then `inner` because Zod v4's\n // `.meta()` returns a new instance, so the meta lives at\n // whichever level the author called .meta() at:\n //\n // z.string().meta({...}).optional() → meta on inner string\n // z.string().optional().meta({...}) → meta on outer optional\n //\n // Both patterns are valid in author code; both should work.\n const meta = readMeta(node) ?? readMeta(inner);\n if (meta && meta.sensitive === true) {\n return { ...base, type: \"password\" };\n }\n if (meta && meta.widget === \"textarea\") {\n const rows =\n typeof meta.rows === \"number\" && meta.rows > 0\n ? meta.rows\n : undefined;\n return {\n ...base,\n type: \"textarea\",\n ...(rows !== undefined ? { rows } : {}),\n };\n }\n const fmt = detectStringFormat(innerDef.checks);\n return { ...base, type: fmt };\n }\n case \"number\": {\n const c = detectNumberConstraints(innerDef.checks);\n return { ...base, type: \"number\", ...c };\n }\n case \"boolean\":\n return { ...base, type: \"boolean\" };\n case \"enum\": {\n const entries = innerDef.entries ?? {};\n return { ...base, type: \"enum\", options: Object.values(entries) };\n }\n case \"array\": {\n const element = innerDef.element;\n // v0.2 supports z.array(z.object(...)) — typed nested form\n // for each item.\n if (element?._def.type === \"object\" && element._def.shape) {\n const childFields = introspectShape(element._def.shape);\n return { ...base, type: \"array\", element: childFields };\n }\n // Phase G follow-up — z.array(z.string()) gets a dedicated\n // string-array widget (one item per line). Surfaced for\n // OAuth scopes and similar string-list configs.\n if (element?._def.type === \"string\") {\n return { ...base, type: \"string-array\" };\n }\n return { ...base, type: \"unsupported\", zodTypeName: \"array\" };\n }\n case \"object\": {\n const shape = innerDef.shape;\n if (shape) {\n return { ...base, type: \"object\", fields: introspectShape(shape) };\n }\n return { ...base, type: \"unsupported\", zodTypeName: \"object\" };\n }\n default:\n return {\n ...base,\n type: \"unsupported\",\n zodTypeName: innerDef.type ?? \"unknown\",\n };\n }\n}\n\nfunction introspectShape(\n shape: Record<string, { _def: ZodDef; description?: string }>,\n): NpThemeSettingsField[] {\n const out: NpThemeSettingsField[] = [];\n for (const [name, raw] of Object.entries(shape)) {\n out.push(introspectField(name, raw));\n }\n return out;\n}\n\n/**\n * Walk a theme's `settingsSchema` (top-level z.object) and emit\n * the form metadata. Returns an empty array when the schema\n * isn't a top-level object — themes are expected to ship\n * `settingsSchema: z.object({...})` (validated implicitly: a\n * non-object top schema yields an empty form, signalling\n * \"nothing to configure\").\n */\nexport function introspectThemeSettingsSchema(\n schema: ZodTypeAny | undefined,\n): NpThemeSettingsField[] {\n if (!schema) return [];\n // Strip any top-level default/optional/nullable wrapper before\n // checking for object shape — themes that wrap their whole\n // schema in `.default({...})` are unusual but valid; without\n // unwrap we'd silently render an empty form.\n const { inner } = unwrap(schema);\n if (inner._def.type !== \"object\" || !inner._def.shape) return [];\n return introspectShape(inner._def.shape);\n}\n"],"mappings":"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","names":["versioned","rawValue","parsed"]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-SBCVAC2Z.js";
|
|
10
10
|
import {
|
|
11
11
|
getLogger
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Q7MK5ZKG.js";
|
|
13
13
|
import {
|
|
14
14
|
getDb
|
|
15
15
|
} from "./chunk-XANPEOJC.js";
|
|
@@ -222,4 +222,4 @@ export {
|
|
|
222
222
|
tSync,
|
|
223
223
|
resetTranslationCache
|
|
224
224
|
};
|
|
225
|
-
//# sourceMappingURL=chunk-
|
|
225
|
+
//# sourceMappingURL=chunk-2X3GBJOT.js.map
|
|
@@ -2,18 +2,18 @@ import {
|
|
|
2
2
|
getCommunityRole,
|
|
3
3
|
memberCan,
|
|
4
4
|
withMemberWrite
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XU2GJJ6Z.js";
|
|
6
6
|
import {
|
|
7
7
|
getMutedTargetIds
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-YEOQJ7WW.js";
|
|
9
9
|
import {
|
|
10
10
|
createNotification,
|
|
11
11
|
extractMentionHandles,
|
|
12
12
|
fanOutMentionNotifications
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-XPD7EQML.js";
|
|
14
14
|
import {
|
|
15
15
|
applyReputation
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-VBVLYFSZ.js";
|
|
17
17
|
import {
|
|
18
18
|
getSpamAdapter
|
|
19
19
|
} from "./chunk-JKXAPSU4.js";
|
|
@@ -22,26 +22,26 @@ import {
|
|
|
22
22
|
} from "./chunk-KU5M27ZC.js";
|
|
23
23
|
import {
|
|
24
24
|
getMediaUrl
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-EWVXP3GP.js";
|
|
26
26
|
import {
|
|
27
27
|
buildWeightedSearchVectorSql,
|
|
28
28
|
deleteDocument,
|
|
29
29
|
findDocuments,
|
|
30
30
|
getDocumentById,
|
|
31
31
|
saveDocument
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-TSCXXBOM.js";
|
|
33
33
|
import {
|
|
34
34
|
deleteMedia
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-EAYUAXW3.js";
|
|
36
36
|
import {
|
|
37
37
|
can
|
|
38
38
|
} from "./chunk-EQ2Z3KMD.js";
|
|
39
39
|
import {
|
|
40
40
|
recordAuditEvent
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-5C22NDW4.js";
|
|
42
42
|
import {
|
|
43
43
|
getCommunitySettings
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-6MRTH734.js";
|
|
45
45
|
import {
|
|
46
46
|
getI18nConfig
|
|
47
47
|
} from "./chunk-4ZLMEKFX.js";
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
} from "./chunk-ZCINJSS4.js";
|
|
65
65
|
import {
|
|
66
66
|
getLogger
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-Q7MK5ZKG.js";
|
|
68
68
|
import {
|
|
69
69
|
getDb
|
|
70
70
|
} from "./chunk-XANPEOJC.js";
|
|
@@ -1587,7 +1587,7 @@ async function searchCollections(opts) {
|
|
|
1587
1587
|
});
|
|
1588
1588
|
if (adapterResult) return adapterResult;
|
|
1589
1589
|
} catch (err) {
|
|
1590
|
-
const { getLogger: getLogger2 } = await import("./logger-
|
|
1590
|
+
const { getLogger: getLogger2 } = await import("./logger-6ZGEKEMK.js");
|
|
1591
1591
|
getLogger2().warn("search adapter threw \u2014 falling back to pg tsvector", {
|
|
1592
1592
|
error: err instanceof Error ? err.message : String(err)
|
|
1593
1593
|
});
|
|
@@ -1956,4 +1956,4 @@ export {
|
|
|
1956
1956
|
revokeMemberRole,
|
|
1957
1957
|
purgeMemberContent
|
|
1958
1958
|
};
|
|
1959
|
-
//# sourceMappingURL=chunk-
|
|
1959
|
+
//# sourceMappingURL=chunk-3SW4L3DL.js.map
|