@wordrhyme/plugin 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/admin/index.d.ts +19 -0
  2. package/dist/admin/index.js +42 -0
  3. package/dist/admin/index.js.map +1 -0
  4. package/dist/artifact.d.ts +17 -0
  5. package/dist/artifact.js +97 -0
  6. package/dist/artifact.js.map +1 -0
  7. package/dist/chunk-3IM3FPTJ.js +1470 -0
  8. package/dist/chunk-3IM3FPTJ.js.map +1 -0
  9. package/dist/chunk-6GDCFR67.js +218 -0
  10. package/dist/chunk-6GDCFR67.js.map +1 -0
  11. package/dist/chunk-7EM22QYB.js +333 -0
  12. package/dist/chunk-7EM22QYB.js.map +1 -0
  13. package/dist/chunk-BI7E5CVM.js +26 -0
  14. package/dist/chunk-BI7E5CVM.js.map +1 -0
  15. package/dist/chunk-BVOTSKM2.js +254 -0
  16. package/dist/chunk-BVOTSKM2.js.map +1 -0
  17. package/dist/chunk-DY44Q4CK.js +188 -0
  18. package/dist/chunk-DY44Q4CK.js.map +1 -0
  19. package/dist/chunk-MZOLSLJ7.js +65 -0
  20. package/dist/chunk-MZOLSLJ7.js.map +1 -0
  21. package/dist/chunk-O4AYK3YP.js +156 -0
  22. package/dist/chunk-O4AYK3YP.js.map +1 -0
  23. package/dist/chunk-UGMYO6AU.js +37 -0
  24. package/dist/chunk-UGMYO6AU.js.map +1 -0
  25. package/dist/client-poND5ovI.d.ts +679 -0
  26. package/dist/client.d.ts +9 -0
  27. package/dist/client.js +68 -0
  28. package/dist/client.js.map +1 -0
  29. package/dist/dev-utils.d.ts +105 -0
  30. package/dist/dev-utils.js +35 -0
  31. package/dist/dev-utils.js.map +1 -0
  32. package/dist/entity-extensions-CnhKoT4k.d.ts +56 -0
  33. package/dist/globalization.d.ts +85 -0
  34. package/dist/globalization.js +53 -0
  35. package/dist/globalization.js.map +1 -0
  36. package/dist/index.d.ts +724 -0
  37. package/dist/index.js +931 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/locale.d.ts +15 -0
  40. package/dist/locale.js +13 -0
  41. package/dist/locale.js.map +1 -0
  42. package/dist/manifest-CTFX-h0w.d.ts +2053 -0
  43. package/dist/react.d.ts +227 -0
  44. package/dist/react.js +226 -0
  45. package/dist/react.js.map +1 -0
  46. package/dist/release-BDJeO54k.d.ts +230 -0
  47. package/dist/server.d.ts +115 -0
  48. package/dist/server.js +194 -0
  49. package/dist/server.js.map +1 -0
  50. package/dist/time.d.ts +34 -0
  51. package/dist/time.js +31 -0
  52. package/dist/time.js.map +1 -0
  53. package/dist/trpc.d.ts +44 -0
  54. package/dist/trpc.js +11 -0
  55. package/dist/trpc.js.map +1 -0
  56. package/dist/types-BJo3_91V.d.ts +1997 -0
  57. package/package.json +92 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/globalization.ts"],"sourcesContent":["import Decimal from 'decimal.js';\n\nexport {\n DEFAULT_LOCALE,\n canonicalizeLocale,\n isLocale,\n normalizeLocale,\n} from './locale';\nimport { DEFAULT_LOCALE, canonicalizeLocale, normalizeLocale } from './locale';\n\nDecimal.set({\n precision: 28,\n rounding: Decimal.ROUND_HALF_EVEN,\n});\n\nexport type TextDirection = 'ltr' | 'rtl';\n\nexport type TranslationMessages = Record<string, string>;\nexport type I18nResourceSnapshot = Record<string, Record<string, TranslationMessages>>;\n\nexport type I18nTextField = string | Record<string, string | null | undefined> | null | undefined;\n\nexport interface LanguageInfo {\n locale: string;\n name: string;\n nativeName?: string | null | undefined;\n isDefault?: boolean | undefined;\n isEnabled?: boolean | undefined;\n sortOrder?: number | null | undefined;\n direction?: TextDirection | undefined;\n}\n\nexport interface CurrencyInfo {\n code: string;\n nameI18n: Record<string, string>;\n symbol: string;\n decimalDigits: number;\n isBase: boolean;\n currentRate: string | null;\n}\n\nexport type CurrencyInfoInput = {\n code: string;\n nameI18n?: Record<string, string> | null | undefined;\n symbol?: string | null | undefined;\n decimalDigits?: number | null | undefined;\n isBase?: boolean | null | undefined;\n currentRate?: string | null | undefined;\n};\n\nexport interface GlobalizationState {\n locale: string;\n direction: TextDirection;\n availableLocales: string[];\n languages?: LanguageInfo[] | undefined;\n currency: string;\n currencies: CurrencyInfo[];\n baseCurrency: CurrencyInfo;\n timezone?: string | undefined;\n fallbackLocale?: string | undefined;\n messages?: TranslationMessages | undefined;\n namespaces?: string[] | undefined;\n resources?: I18nResourceSnapshot | undefined;\n versions?: Record<string, string> | undefined;\n t?: Translator | undefined;\n p?: PriceFormatter | undefined;\n changeLocale?: ((locale: string) => void | Promise<void>) | undefined;\n changeCurrency?: ((currencyCode: string) => void | Promise<void>) | undefined;\n}\n\nexport interface FormatPriceOptions {\n showSymbol?: boolean | undefined;\n currencyDisplay?: 'symbol' | 'code' | 'name' | 'narrowSymbol' | undefined;\n notation?: 'standard' | 'compact' | undefined;\n signDisplay?: 'auto' | 'always' | 'exceptZero' | 'never' | undefined;\n decimalDigits?: number | undefined;\n locale?: string | undefined;\n toCurrency?: string | CurrencyInfo | undefined;\n}\n\nexport type Translator = (\n key: string,\n paramsOrFallback?: Record<string, string | number> | string,\n) => string;\n\nexport type PriceFormatter = (\n cents: number,\n fromCurrencyOrOptions?: string | CurrencyInfo | FormatPriceOptions,\n options?: FormatPriceOptions,\n) => string;\n\nexport const DEFAULT_CURRENCY: CurrencyInfo = {\n code: 'USD',\n nameI18n: { 'en-US': 'US Dollar', 'zh-CN': '美元' },\n symbol: '$',\n decimalDigits: 2,\n isBase: true,\n currentRate: '1',\n};\n\nconst RTL_LANGUAGE_CODES = new Set(['ar', 'he', 'fa', 'ur']);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === 'object' && !Array.isArray(value));\n}\n\nfunction isCurrencyInfo(value: unknown): value is CurrencyInfo {\n return isRecord(value) && typeof value['code'] === 'string';\n}\n\nfunction isCurrencyCatalog(value: readonly CurrencyInfo[] | CurrencyInfo): value is readonly CurrencyInfo[] {\n return Array.isArray(value);\n}\n\nfunction readRate(currency: CurrencyInfo): Decimal {\n if (currency.isBase) return new Decimal(1);\n\n try {\n const rate = new Decimal(currency.currentRate ?? '1');\n return rate.gt(0) ? rate : new Decimal(1);\n } catch {\n return new Decimal(1);\n }\n}\n\nfunction minorUnitFactor(currency: CurrencyInfo): Decimal {\n return new Decimal(10).pow(Math.max(0, currency.decimalDigits));\n}\n\nexport function getTextDirection(locale: string): TextDirection {\n const languageCode = normalizeLocale(locale, DEFAULT_LOCALE).split('-')[0]?.toLowerCase();\n return languageCode && RTL_LANGUAGE_CODES.has(languageCode) ? 'rtl' : 'ltr';\n}\n\nexport function normalizeCurrencyInfo(\n currency: CurrencyInfoInput,\n fallback: CurrencyInfo = DEFAULT_CURRENCY,\n): CurrencyInfo {\n const code = currency.code.toUpperCase();\n return {\n code,\n nameI18n: currency.nameI18n ?? (code === fallback.code ? fallback.nameI18n : {}),\n symbol: currency.symbol ?? (code === fallback.code ? fallback.symbol : code),\n decimalDigits: typeof currency.decimalDigits === 'number' ? currency.decimalDigits : fallback.decimalDigits,\n isBase: currency.isBase ?? code === fallback.code,\n currentRate: currency.isBase ? '1' : (currency.currentRate ?? null),\n };\n}\n\nexport function normalizeCurrencies(currencies: readonly CurrencyInfoInput[]): CurrencyInfo[] {\n if (currencies.length === 0) return [DEFAULT_CURRENCY];\n const normalized = currencies.map((currency) => normalizeCurrencyInfo(currency));\n const hasBase = normalized.some((currency) => currency.isBase);\n if (hasBase) return normalized;\n\n return normalized.map((currency, index) => ({\n ...currency,\n isBase: index === 0,\n currentRate: index === 0 ? '1' : currency.currentRate,\n }));\n}\n\nexport function findCurrency(\n currencies: readonly CurrencyInfo[],\n currencyCode: string | undefined,\n): CurrencyInfo | undefined {\n if (!currencyCode) return undefined;\n const normalizedCode = currencyCode.toUpperCase();\n return currencies.find((currency) => currency.code.toUpperCase() === normalizedCode);\n}\n\nexport function getBaseCurrency(currencies: readonly CurrencyInfo[]): CurrencyInfo {\n return currencies.find((currency) => currency.isBase) ?? currencies[0] ?? DEFAULT_CURRENCY;\n}\n\nexport function resolveCurrencyInfo(\n currency: string | CurrencyInfo | undefined,\n currencies: readonly CurrencyInfo[],\n fallback: CurrencyInfo = getBaseCurrency(currencies),\n): CurrencyInfo {\n if (isCurrencyInfo(currency)) return normalizeCurrencyInfo(currency, fallback);\n return findCurrency(currencies, currency) ?? normalizeCurrencyInfo({ code: currency ?? fallback.code }, fallback);\n}\n\nexport function bankersRound(value: number, decimalDigits: number): number {\n const decimal = new Decimal(value);\n const factor = new Decimal(10).pow(decimalDigits);\n return decimal.times(factor).round().div(factor).toNumber();\n}\n\nexport function toCents(displayAmount: number, decimalDigits: number): number {\n const factor = new Decimal(10).pow(decimalDigits);\n return new Decimal(displayAmount).times(factor).round().toNumber();\n}\n\nexport function fromCents(cents: number, decimalDigits: number): number {\n const factor = new Decimal(10).pow(decimalDigits);\n return new Decimal(cents).div(factor).toNumber();\n}\n\nexport function convertCurrency(\n cents: number,\n fromCurrency: CurrencyInfo,\n toCurrency: CurrencyInfo,\n currenciesOrBaseCurrency: readonly CurrencyInfo[] | CurrencyInfo,\n): number {\n if (fromCurrency.code === toCurrency.code) return cents;\n\n const catalog = isCurrencyCatalog(currenciesOrBaseCurrency)\n ? currenciesOrBaseCurrency\n : [currenciesOrBaseCurrency, fromCurrency, toCurrency];\n const baseCurrency = isCurrencyCatalog(currenciesOrBaseCurrency)\n ? getBaseCurrency(catalog)\n : currenciesOrBaseCurrency;\n\n const from = normalizeCurrencyInfo(fromCurrency, baseCurrency);\n const to = normalizeCurrencyInfo(toCurrency, baseCurrency);\n const sourceMinor = new Decimal(cents);\n const sourceMajor = sourceMinor.div(minorUnitFactor(from));\n const baseMajor = sourceMajor.div(readRate(from));\n const targetMajor = baseMajor.times(readRate(to));\n return targetMajor.times(minorUnitFactor(to)).round().toNumber();\n}\n\nexport function formatCurrencyAmount(\n cents: number,\n currency: CurrencyInfo,\n locale: string,\n options: FormatPriceOptions = {},\n): string {\n const {\n showSymbol = true,\n currencyDisplay = 'symbol',\n notation = 'standard',\n signDisplay = 'auto',\n decimalDigits,\n } = options;\n const digits = decimalDigits ?? currency.decimalDigits;\n const displayAmount = fromCents(cents, currency.decimalDigits);\n\n try {\n const formatter = new Intl.NumberFormat(locale, showSymbol ? {\n style: 'currency',\n currency: currency.code,\n currencyDisplay,\n notation,\n signDisplay,\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n } : {\n style: 'decimal',\n notation,\n signDisplay,\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n });\n return formatter.format(displayAmount);\n } catch {\n const symbol = showSymbol ? currency.symbol : '';\n return `${symbol}${displayAmount.toFixed(digits)}`;\n }\n}\n\nexport function formatPrice(\n cents: number,\n fromCurrency: string | CurrencyInfo,\n state: GlobalizationState,\n options: FormatPriceOptions = {},\n): string {\n const currencies = normalizeCurrencies(state.currencies.length ? state.currencies : [state.baseCurrency]);\n const baseCurrency = normalizeCurrencyInfo(state.baseCurrency, getBaseCurrency(currencies));\n const sourceCurrency = resolveCurrencyInfo(fromCurrency, currencies, baseCurrency);\n const targetCurrency = resolveCurrencyInfo(options.toCurrency ?? state.currency, currencies, baseCurrency);\n const converted = convertCurrency(cents, sourceCurrency, targetCurrency, currencies);\n\n return formatCurrencyAmount(\n converted,\n targetCurrency,\n options.locale ?? state.locale,\n options,\n );\n}\n\nexport function getI18nText(\n field: I18nTextField,\n locale: string,\n fallbackLocale = 'en-US',\n): string {\n if (typeof field === 'string') return field;\n if (!field || typeof field !== 'object') return '';\n\n const normalizedLocale = normalizeLocale(locale, fallbackLocale);\n const normalizedFallbackLocale = normalizeLocale(fallbackLocale);\n const languageCode = normalizedLocale.split('-')[0];\n const fallbackLanguageCode = normalizedFallbackLocale.split('-')[0];\n const candidates = [\n field[normalizedLocale],\n languageCode ? field[languageCode] : undefined,\n field[normalizedFallbackLocale],\n fallbackLanguageCode ? field[fallbackLanguageCode] : undefined,\n ...Object.values(field),\n ];\n\n return candidates.find((value): value is string => typeof value === 'string' && value.length > 0) ?? '';\n}\n\nfunction resolveMessageKey(\n messages: TranslationMessages,\n key: string,\n params: Record<string, string | number> | undefined,\n locale: string,\n): string {\n const context = typeof params?.['context'] === 'string' ? params['context'] : undefined;\n const count = typeof params?.['count'] === 'number' ? params['count'] : undefined;\n const candidates: string[] = [];\n\n if (count !== undefined) {\n const category = new Intl.PluralRules(locale).select(count);\n if (context) candidates.push(`${key}_${context}_${category}`, `${key}_${context}_other`);\n candidates.push(`${key}_${category}`, `${key}_other`);\n }\n if (context) candidates.push(`${key}_${context}`);\n candidates.push(key);\n\n return candidates.find((candidate) => messages[candidate] !== undefined) ?? key;\n}\n\nexport function createTranslator(\n messages: TranslationMessages | undefined,\n locale = DEFAULT_LOCALE,\n): Translator {\n const translations = messages ?? {};\n const normalizedLocale = canonicalizeLocale(locale) ?? DEFAULT_LOCALE;\n return (key, paramsOrFallback) => {\n const params = paramsOrFallback && typeof paramsOrFallback === 'object'\n ? paramsOrFallback\n : undefined;\n const resolvedKey = resolveMessageKey(translations, key, params, normalizedLocale);\n let value = translations[resolvedKey];\n if (!value) {\n return typeof paramsOrFallback === 'string' ? paramsOrFallback : key;\n }\n if (params) {\n for (const [name, replacement] of Object.entries(params)) {\n value = value\n .replace(new RegExp(`\\\\{\\\\{${name}\\\\}\\\\}`, 'g'), String(replacement))\n .replace(new RegExp(`\\\\{${name}\\\\}`, 'g'), String(replacement));\n }\n }\n return value;\n };\n}\n\nfunction isFormatPriceOptions(value: unknown): value is FormatPriceOptions {\n return isRecord(value) && !('code' in value);\n}\n\nexport function createPriceFormatter(\n state: GlobalizationState,\n defaultFromCurrency?: string | CurrencyInfo,\n): PriceFormatter {\n return (cents, fromCurrencyOrOptions, options) => {\n const fromCurrency = isFormatPriceOptions(fromCurrencyOrOptions)\n ? defaultFromCurrency ?? state.baseCurrency\n : fromCurrencyOrOptions ?? defaultFromCurrency ?? state.baseCurrency;\n const formatOptions = isFormatPriceOptions(fromCurrencyOrOptions)\n ? fromCurrencyOrOptions\n : options;\n\n return formatPrice(cents, fromCurrency, state, formatOptions);\n };\n}\n\nexport function withGlobalizationHelpers(\n state: GlobalizationState,\n handlers: Pick<GlobalizationState, 'changeLocale' | 'changeCurrency'> = {},\n): GlobalizationState {\n return {\n ...state,\n t: state.t ?? createTranslator(state.messages, state.locale),\n p: state.p ?? createPriceFormatter(state),\n ...handlers,\n };\n}\n\nexport function buildGlobalizationUrl(\n url: string | URL,\n updates: { locale?: string | null | undefined; currency?: string | null | undefined },\n): string {\n const raw = String(url);\n const isAbsolute = /^[a-z][a-z\\d+\\-.]*:/i.test(raw);\n const parsed = new URL(raw, 'https://wordrhyme.local');\n\n if (updates.locale === null) {\n parsed.searchParams.delete('lang');\n } else if (updates.locale) {\n parsed.searchParams.set('lang', updates.locale);\n }\n\n if (updates.currency === null) {\n parsed.searchParams.delete('currency');\n } else if (updates.currency) {\n parsed.searchParams.set('currency', updates.currency.toUpperCase());\n }\n\n return isAbsolute ? parsed.toString() : `${parsed.pathname}${parsed.search}${parsed.hash}`;\n}\n\nexport { Decimal };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,188 @@
1
+ // src/release.ts
2
+ import { z } from "zod";
3
+ var PLUGIN_ARCHIVE_MEDIA_TYPE = "application/vnd.wordrhyme.plugin+zip";
4
+ var PLUGIN_RELEASE_SCHEMA_VERSION = 1;
5
+ var REGISTRY_RELEASE_SCHEMA_VERSION = 1;
6
+ var REGISTRY_RELEASE_SIGNATURE_DOMAIN = "wordrhyme.registry-release.v1\0";
7
+ var REGISTRY_CATALOG_SIGNATURE_DOMAIN = "wordrhyme.registry-catalog-page.v1\0";
8
+ var pluginIdSchema = z.string().min(3).max(128).regex(/^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/, "pluginId must be in reverse domain notation");
9
+ var versionSchema = z.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/, "version must be valid semver");
10
+ var sha256Schema = z.string().regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex");
11
+ var pluginArchivePathSchema = z.string().min(1).max(512).refine((value) => !value.startsWith("/") && !value.includes("\\"), {
12
+ message: "archive paths must be relative POSIX paths"
13
+ }).refine((value) => value.split("/").every((segment) => segment !== "" && segment !== "." && segment !== ".."), {
14
+ message: "archive paths must not contain empty, dot, or parent segments"
15
+ });
16
+ var pluginReleaseFileSchema = z.object({
17
+ path: pluginArchivePathSchema,
18
+ size: z.number().int().nonnegative(),
19
+ sha256: sha256Schema
20
+ });
21
+ var pluginReleaseSchema = z.object({
22
+ schemaVersion: z.literal(PLUGIN_RELEASE_SCHEMA_VERSION),
23
+ pluginId: pluginIdSchema,
24
+ version: versionSchema,
25
+ createdAt: z.iso.datetime({ offset: true }),
26
+ mediaType: z.literal(PLUGIN_ARCHIVE_MEDIA_TYPE),
27
+ files: z.array(pluginReleaseFileSchema).min(1),
28
+ sbom: z.object({
29
+ path: pluginArchivePathSchema,
30
+ format: z.literal("spdx-json")
31
+ })
32
+ }).superRefine((release, ctx) => {
33
+ const paths = /* @__PURE__ */ new Set();
34
+ for (const [index, file] of release.files.entries()) {
35
+ if (paths.has(file.path)) {
36
+ ctx.addIssue({
37
+ code: "custom",
38
+ path: ["files", index, "path"],
39
+ message: `duplicate release file: ${file.path}`
40
+ });
41
+ }
42
+ paths.add(file.path);
43
+ }
44
+ if (!paths.has("manifest.json")) {
45
+ ctx.addIssue({
46
+ code: "custom",
47
+ path: ["files"],
48
+ message: "release must include manifest.json"
49
+ });
50
+ }
51
+ if (!paths.has(release.sbom.path)) {
52
+ ctx.addIssue({
53
+ code: "custom",
54
+ path: ["sbom", "path"],
55
+ message: "SBOM path must reference a release file"
56
+ });
57
+ }
58
+ });
59
+ var pluginSignatureSchema = z.object({
60
+ schemaVersion: z.literal(PLUGIN_RELEASE_SCHEMA_VERSION),
61
+ pluginId: pluginIdSchema,
62
+ version: versionSchema,
63
+ algorithm: z.literal("ed25519"),
64
+ keyId: z.string().min(1).max(160),
65
+ signedAt: z.iso.datetime({ offset: true }),
66
+ releaseSha256: sha256Schema,
67
+ signature: z.string().min(1)
68
+ });
69
+ var registryReleaseEnvelopeSchema = z.object({
70
+ schemaVersion: z.literal(REGISTRY_RELEASE_SCHEMA_VERSION),
71
+ pluginId: pluginIdSchema,
72
+ version: versionSchema,
73
+ publisherId: z.string().min(1).max(160),
74
+ state: z.literal("published"),
75
+ trustLevel: z.enum(["first_party", "third_party"]),
76
+ artifactUrl: z.url(),
77
+ artifactSha256: sha256Schema,
78
+ releaseSha256: sha256Schema,
79
+ publishedAt: z.iso.datetime({ offset: true })
80
+ });
81
+ var registrySignatureSchema = z.object({
82
+ schemaVersion: z.literal(REGISTRY_RELEASE_SCHEMA_VERSION),
83
+ algorithm: z.literal("ed25519"),
84
+ keyId: z.string().min(1).max(160),
85
+ signedAt: z.iso.datetime({ offset: true }),
86
+ envelopeSha256: sha256Schema,
87
+ signature: z.string().min(1)
88
+ });
89
+ var registryCatalogPageEnvelopeSchema = z.object({
90
+ schemaVersion: z.literal(REGISTRY_RELEASE_SCHEMA_VERSION),
91
+ snapshotId: z.string().min(1).max(160),
92
+ generatedAt: z.iso.datetime({ offset: true }),
93
+ cursor: z.string().nullable(),
94
+ nextCursor: z.string().nullable(),
95
+ releasesSha256: sha256Schema
96
+ });
97
+ function canonicalRegistryReleaseEnvelope(input) {
98
+ const envelope = registryReleaseEnvelopeSchema.parse(input);
99
+ return JSON.stringify({
100
+ schemaVersion: envelope.schemaVersion,
101
+ pluginId: envelope.pluginId,
102
+ version: envelope.version,
103
+ publisherId: envelope.publisherId,
104
+ state: envelope.state,
105
+ trustLevel: envelope.trustLevel,
106
+ artifactUrl: envelope.artifactUrl,
107
+ artifactSha256: envelope.artifactSha256,
108
+ releaseSha256: envelope.releaseSha256,
109
+ publishedAt: envelope.publishedAt
110
+ });
111
+ }
112
+ function registryReleaseSignaturePayload(input) {
113
+ return new TextEncoder().encode(
114
+ `${REGISTRY_RELEASE_SIGNATURE_DOMAIN}${canonicalRegistryReleaseEnvelope(input)}`
115
+ );
116
+ }
117
+ function canonicalRegistryCatalogPageEnvelope(input) {
118
+ const envelope = registryCatalogPageEnvelopeSchema.parse(input);
119
+ return JSON.stringify({
120
+ schemaVersion: envelope.schemaVersion,
121
+ snapshotId: envelope.snapshotId,
122
+ generatedAt: envelope.generatedAt,
123
+ cursor: envelope.cursor,
124
+ nextCursor: envelope.nextCursor,
125
+ releasesSha256: envelope.releasesSha256
126
+ });
127
+ }
128
+ function registryCatalogPageSignaturePayload(input) {
129
+ return new TextEncoder().encode(
130
+ `${REGISTRY_CATALOG_SIGNATURE_DOMAIN}${canonicalRegistryCatalogPageEnvelope(input)}`
131
+ );
132
+ }
133
+ var pluginRegistryReleaseSchema = z.object({
134
+ pluginId: pluginIdSchema,
135
+ version: versionSchema,
136
+ publisherId: z.string().min(1).max(160),
137
+ state: z.enum(["published", "archived", "suspended", "removed"]),
138
+ trustLevel: z.enum(["first_party", "third_party"]),
139
+ manifest: z.record(z.string(), z.unknown()),
140
+ release: pluginReleaseSchema,
141
+ artifactUrl: z.url(),
142
+ artifactSha256: sha256Schema,
143
+ releaseSha256: sha256Schema,
144
+ publisherSignature: pluginSignatureSchema.nullable(),
145
+ /** @deprecated Compatibility alias for publisherSignature. */
146
+ signature: pluginSignatureSchema.nullable().optional(),
147
+ registrySignature: registrySignatureSchema,
148
+ publishedAt: z.iso.datetime({ offset: true })
149
+ });
150
+ var pluginRegistryCatalogSchema = z.object({
151
+ schemaVersion: z.literal(PLUGIN_RELEASE_SCHEMA_VERSION),
152
+ snapshotId: z.string().min(1).max(160),
153
+ generatedAt: z.iso.datetime({ offset: true }),
154
+ releases: z.array(pluginRegistryReleaseSchema),
155
+ nextCursor: z.string().nullable(),
156
+ catalogSignature: registrySignatureSchema
157
+ });
158
+ function canonicalJson(value) {
159
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
160
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
161
+ const record = value;
162
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
163
+ }
164
+ function registryCatalogReleasesPayload(input) {
165
+ const releases = z.array(pluginRegistryReleaseSchema).parse(input);
166
+ return new TextEncoder().encode(canonicalJson(releases));
167
+ }
168
+
169
+ export {
170
+ PLUGIN_ARCHIVE_MEDIA_TYPE,
171
+ PLUGIN_RELEASE_SCHEMA_VERSION,
172
+ REGISTRY_CATALOG_SIGNATURE_DOMAIN,
173
+ pluginArchivePathSchema,
174
+ pluginReleaseFileSchema,
175
+ pluginReleaseSchema,
176
+ pluginSignatureSchema,
177
+ registryReleaseEnvelopeSchema,
178
+ registrySignatureSchema,
179
+ registryCatalogPageEnvelopeSchema,
180
+ canonicalRegistryReleaseEnvelope,
181
+ registryReleaseSignaturePayload,
182
+ canonicalRegistryCatalogPageEnvelope,
183
+ registryCatalogPageSignaturePayload,
184
+ pluginRegistryReleaseSchema,
185
+ pluginRegistryCatalogSchema,
186
+ registryCatalogReleasesPayload
187
+ };
188
+ //# sourceMappingURL=chunk-DY44Q4CK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/release.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const PLUGIN_ARCHIVE_MEDIA_TYPE = \"application/vnd.wordrhyme.plugin+zip\";\nexport const PLUGIN_RELEASE_SCHEMA_VERSION = 1 as const;\nexport const REGISTRY_RELEASE_SCHEMA_VERSION = 1 as const;\nexport const REGISTRY_RELEASE_SIGNATURE_DOMAIN = \"wordrhyme.registry-release.v1\\0\";\nexport const REGISTRY_CATALOG_SIGNATURE_DOMAIN = \"wordrhyme.registry-catalog-page.v1\\0\";\n\nconst pluginIdSchema = z\n .string()\n .min(3)\n .max(128)\n .regex(/^[a-z][a-z0-9-]*(\\.[a-z][a-z0-9-]*)+$/, \"pluginId must be in reverse domain notation\");\n\nconst versionSchema = z\n .string()\n .regex(/^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/, \"version must be valid semver\");\n\nconst sha256Schema = z.string().regex(/^[a-f0-9]{64}$/, \"sha256 must be lowercase hex\");\n\nexport const pluginArchivePathSchema = z\n .string()\n .min(1)\n .max(512)\n .refine((value) => !value.startsWith(\"/\") && !value.includes(\"\\\\\"), {\n message: \"archive paths must be relative POSIX paths\",\n })\n .refine((value) => value.split(\"/\").every((segment) => segment !== \"\" && segment !== \".\" && segment !== \"..\"), {\n message: \"archive paths must not contain empty, dot, or parent segments\",\n });\n\nexport const pluginReleaseFileSchema = z.object({\n path: pluginArchivePathSchema,\n size: z.number().int().nonnegative(),\n sha256: sha256Schema,\n});\n\nexport const pluginReleaseSchema = z\n .object({\n schemaVersion: z.literal(PLUGIN_RELEASE_SCHEMA_VERSION),\n pluginId: pluginIdSchema,\n version: versionSchema,\n createdAt: z.iso.datetime({ offset: true }),\n mediaType: z.literal(PLUGIN_ARCHIVE_MEDIA_TYPE),\n files: z.array(pluginReleaseFileSchema).min(1),\n sbom: z.object({\n path: pluginArchivePathSchema,\n format: z.literal(\"spdx-json\"),\n }),\n })\n .superRefine((release, ctx) => {\n const paths = new Set<string>();\n for (const [index, file] of release.files.entries()) {\n if (paths.has(file.path)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"files\", index, \"path\"],\n message: `duplicate release file: ${file.path}`,\n });\n }\n paths.add(file.path);\n }\n\n if (!paths.has(\"manifest.json\")) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"files\"],\n message: \"release must include manifest.json\",\n });\n }\n\n if (!paths.has(release.sbom.path)) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"sbom\", \"path\"],\n message: \"SBOM path must reference a release file\",\n });\n }\n });\n\nexport const pluginSignatureSchema = z.object({\n schemaVersion: z.literal(PLUGIN_RELEASE_SCHEMA_VERSION),\n pluginId: pluginIdSchema,\n version: versionSchema,\n algorithm: z.literal(\"ed25519\"),\n keyId: z.string().min(1).max(160),\n signedAt: z.iso.datetime({ offset: true }),\n releaseSha256: sha256Schema,\n signature: z.string().min(1),\n});\n\nexport const registryReleaseEnvelopeSchema = z.object({\n schemaVersion: z.literal(REGISTRY_RELEASE_SCHEMA_VERSION),\n pluginId: pluginIdSchema,\n version: versionSchema,\n publisherId: z.string().min(1).max(160),\n state: z.literal(\"published\"),\n trustLevel: z.enum([\"first_party\", \"third_party\"]),\n artifactUrl: z.url(),\n artifactSha256: sha256Schema,\n releaseSha256: sha256Schema,\n publishedAt: z.iso.datetime({ offset: true }),\n});\n\nexport const registrySignatureSchema = z.object({\n schemaVersion: z.literal(REGISTRY_RELEASE_SCHEMA_VERSION),\n algorithm: z.literal(\"ed25519\"),\n keyId: z.string().min(1).max(160),\n signedAt: z.iso.datetime({ offset: true }),\n envelopeSha256: sha256Schema,\n signature: z.string().min(1),\n});\n\nexport const registryCatalogPageEnvelopeSchema = z.object({\n schemaVersion: z.literal(REGISTRY_RELEASE_SCHEMA_VERSION),\n snapshotId: z.string().min(1).max(160),\n generatedAt: z.iso.datetime({ offset: true }),\n cursor: z.string().nullable(),\n nextCursor: z.string().nullable(),\n releasesSha256: sha256Schema,\n});\n\n/**\n * The Registry signature contract intentionally uses an explicit field order.\n * Do not replace this with JSON.stringify(input): callers may construct the\n * same envelope with a different property insertion order.\n */\nexport function canonicalRegistryReleaseEnvelope(input: RegistryReleaseEnvelope): string {\n const envelope = registryReleaseEnvelopeSchema.parse(input);\n return JSON.stringify({\n schemaVersion: envelope.schemaVersion,\n pluginId: envelope.pluginId,\n version: envelope.version,\n publisherId: envelope.publisherId,\n state: envelope.state,\n trustLevel: envelope.trustLevel,\n artifactUrl: envelope.artifactUrl,\n artifactSha256: envelope.artifactSha256,\n releaseSha256: envelope.releaseSha256,\n publishedAt: envelope.publishedAt,\n });\n}\n\nexport function registryReleaseSignaturePayload(input: RegistryReleaseEnvelope): Uint8Array {\n return new TextEncoder().encode(\n `${REGISTRY_RELEASE_SIGNATURE_DOMAIN}${canonicalRegistryReleaseEnvelope(input)}`,\n );\n}\n\nexport function canonicalRegistryCatalogPageEnvelope(input: RegistryCatalogPageEnvelope): string {\n const envelope = registryCatalogPageEnvelopeSchema.parse(input);\n return JSON.stringify({\n schemaVersion: envelope.schemaVersion,\n snapshotId: envelope.snapshotId,\n generatedAt: envelope.generatedAt,\n cursor: envelope.cursor,\n nextCursor: envelope.nextCursor,\n releasesSha256: envelope.releasesSha256,\n });\n}\n\nexport function registryCatalogPageSignaturePayload(input: RegistryCatalogPageEnvelope): Uint8Array {\n return new TextEncoder().encode(\n `${REGISTRY_CATALOG_SIGNATURE_DOMAIN}${canonicalRegistryCatalogPageEnvelope(input)}`,\n );\n}\n\nexport const pluginRegistryReleaseSchema = z.object({\n pluginId: pluginIdSchema,\n version: versionSchema,\n publisherId: z.string().min(1).max(160),\n state: z.enum([\"published\", \"archived\", \"suspended\", \"removed\"]),\n trustLevel: z.enum([\"first_party\", \"third_party\"]),\n manifest: z.record(z.string(), z.unknown()),\n release: pluginReleaseSchema,\n artifactUrl: z.url(),\n artifactSha256: sha256Schema,\n releaseSha256: sha256Schema,\n publisherSignature: pluginSignatureSchema.nullable(),\n /** @deprecated Compatibility alias for publisherSignature. */\n signature: pluginSignatureSchema.nullable().optional(),\n registrySignature: registrySignatureSchema,\n publishedAt: z.iso.datetime({ offset: true }),\n});\n\nexport const pluginRegistryCatalogSchema = z.object({\n schemaVersion: z.literal(PLUGIN_RELEASE_SCHEMA_VERSION),\n snapshotId: z.string().min(1).max(160),\n generatedAt: z.iso.datetime({ offset: true }),\n releases: z.array(pluginRegistryReleaseSchema),\n nextCursor: z.string().nullable(),\n catalogSignature: registrySignatureSchema,\n});\n\nfunction canonicalJson(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalJson).join(\",\")}]`;\n const record = value as Record<string, unknown>;\n return `{${Object.keys(record)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`)\n .join(\",\")}}`;\n}\n\nexport function registryCatalogReleasesPayload(input: PluginRegistryRelease[]): Uint8Array {\n const releases = z.array(pluginRegistryReleaseSchema).parse(input);\n return new TextEncoder().encode(canonicalJson(releases));\n}\n\nexport type PluginReleaseFile = z.infer<typeof pluginReleaseFileSchema>;\nexport type PluginRelease = z.infer<typeof pluginReleaseSchema>;\nexport type PluginSignature = z.infer<typeof pluginSignatureSchema>;\nexport type RegistryReleaseEnvelope = z.infer<typeof registryReleaseEnvelopeSchema>;\nexport type RegistrySignature = z.infer<typeof registrySignatureSchema>;\nexport type RegistryCatalogPageEnvelope = z.infer<typeof registryCatalogPageEnvelopeSchema>;\nexport type PluginRegistryRelease = z.infer<typeof pluginRegistryReleaseSchema>;\nexport type PluginRegistryCatalog = z.infer<typeof pluginRegistryCatalogSchema>;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,65 @@
1
+ // src/extension-helpers.ts
2
+ function stripUndefined(obj) {
3
+ const result = {};
4
+ for (const [k, v] of Object.entries(obj)) {
5
+ if (v !== void 0) result[k] = v;
6
+ }
7
+ return result;
8
+ }
9
+ function defineExtension(ext) {
10
+ return stripUndefined({
11
+ ...ext,
12
+ targets: ext.targets.map((target) => stripUndefined(target))
13
+ });
14
+ }
15
+ function navExtension(ext) {
16
+ const { path, order, requiredPermission, hidden, ...rest } = ext;
17
+ const target = stripUndefined({
18
+ slot: "nav.sidebar",
19
+ path,
20
+ order,
21
+ requiredPermission
22
+ });
23
+ return defineExtension({ ...stripUndefined(rest), targets: [target], ...hidden ? { hidden: true } : {} });
24
+ }
25
+ function routeExtension(ext) {
26
+ const { path, order, params, ...rest } = ext;
27
+ const target = stripUndefined({
28
+ slot: "plugin.route",
29
+ path,
30
+ order,
31
+ params
32
+ });
33
+ return defineExtension({ ...stripUndefined(rest), targets: [target] });
34
+ }
35
+ function settingsExtension(ext) {
36
+ const { order, visibility, ...rest } = ext;
37
+ const target = stripUndefined({
38
+ slot: "settings.plugin",
39
+ order,
40
+ visibility
41
+ });
42
+ return defineExtension({ ...stripUndefined(rest), targets: [target] });
43
+ }
44
+ function dashboardExtension(ext) {
45
+ const { order, colSpan, ...rest } = ext;
46
+ const target = stripUndefined({
47
+ slot: "dashboard.widgets",
48
+ order,
49
+ colSpan
50
+ });
51
+ return defineExtension({ ...stripUndefined(rest), targets: [target] });
52
+ }
53
+ function multiSlotExtension(ext) {
54
+ return defineExtension(ext);
55
+ }
56
+
57
+ export {
58
+ defineExtension,
59
+ navExtension,
60
+ routeExtension,
61
+ settingsExtension,
62
+ dashboardExtension,
63
+ multiSlotExtension
64
+ };
65
+ //# sourceMappingURL=chunk-MZOLSLJ7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/extension-helpers.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ComponentType = (props: any) => any;\n\n// ─── 类型定义(与 admin 侧 extension-types.ts 保持一致) ───\n\nexport type Target = NavTarget | NavGroupTarget | RouteTarget | SettingsTarget | DashboardTarget | GenericTarget;\n\nexport interface NavTarget {\n slot: 'nav.sidebar';\n path: string;\n icon?: string;\n order?: number;\n requiredPermission?: string;\n parent?: string;\n}\n\nexport interface NavGroupTarget {\n slot: 'nav.sidebar.group';\n path?: string;\n icon?: string;\n order?: number;\n}\n\nexport interface RouteTarget {\n slot: 'plugin.route';\n path: string;\n order?: number;\n params?: Record<string, string>;\n}\n\nexport interface SettingsTarget {\n slot: 'settings.plugin';\n category?: string;\n order?: number;\n visibility?: 'platform' | 'all';\n}\n\nexport interface DashboardTarget {\n slot: 'dashboard.widgets' | 'dashboard.overview';\n order?: number;\n colSpan?: 1 | 2 | 3 | 4;\n}\n\nexport interface GenericTarget {\n slot: string;\n order?: number;\n}\n\nexport interface SlotContext {\n [key: string]: unknown;\n}\n\nexport interface UIExtensionDef {\n id: string;\n label: string;\n icon?: string;\n category?: string;\n component?: ComponentType;\n remoteComponent?: string;\n targets: Target[];\n /** If true, the extension is registered for component matching but hidden from sidebar */\n hidden?: boolean;\n}\n\nexport type ExtensionComponentMap = Record<string, ComponentType>;\nexport type ToolbarHandlerMap = Record<string, () => void>;\n\n/** Remove undefined values from an object to satisfy exactOptionalPropertyTypes */\nfunction stripUndefined<T extends object>(obj: T): T {\n const result = {} as Record<string, unknown>;\n for (const [k, v] of Object.entries(obj)) {\n if (v !== undefined) result[k] = v;\n }\n return result as T;\n}\n\n// ─── 辅助函数 ───\n\nexport function defineExtension(ext: UIExtensionDef): UIExtensionDef {\n return stripUndefined({\n ...ext,\n targets: ext.targets.map((target) => stripUndefined(target)),\n });\n}\n\nexport function navExtension(ext: {\n id: string;\n label: string;\n icon?: string;\n component?: ComponentType;\n remoteComponent?: string;\n path: string;\n order?: number;\n requiredPermission?: string;\n /** If true, registers component but hides from sidebar (menu managed by host) */\n hidden?: boolean;\n}): UIExtensionDef {\n const { path, order, requiredPermission, hidden, ...rest } = ext;\n const target: NavTarget = stripUndefined({\n slot: 'nav.sidebar' as const,\n path,\n order,\n requiredPermission,\n }) as NavTarget;\n return defineExtension({ ...stripUndefined(rest), targets: [target], ...(hidden ? { hidden: true } : {}) });\n}\n\nexport function routeExtension(ext: {\n id: string;\n label: string;\n icon?: string;\n component?: ComponentType;\n remoteComponent?: string;\n path: string;\n order?: number;\n params?: Record<string, string>;\n}): UIExtensionDef {\n const { path, order, params, ...rest } = ext;\n const target: RouteTarget = stripUndefined({\n slot: 'plugin.route' as const,\n path,\n order,\n params,\n }) as RouteTarget;\n return defineExtension({ ...stripUndefined(rest), targets: [target] });\n}\n\nexport function settingsExtension(ext: {\n id: string;\n label: string;\n icon?: string;\n component?: ComponentType;\n remoteComponent?: string;\n order?: number;\n category?: string;\n visibility?: 'platform' | 'all';\n}): UIExtensionDef {\n const { order, visibility, ...rest } = ext;\n const target: SettingsTarget = stripUndefined({\n slot: 'settings.plugin' as const,\n order,\n visibility,\n }) as SettingsTarget;\n return defineExtension({ ...stripUndefined(rest), targets: [target] });\n}\n\nexport function dashboardExtension(ext: {\n id: string;\n label: string;\n icon?: string;\n component?: ComponentType;\n remoteComponent?: string;\n order?: number;\n colSpan?: 1 | 2 | 3 | 4;\n}): UIExtensionDef {\n const { order, colSpan, ...rest } = ext;\n const target: DashboardTarget = stripUndefined({\n slot: 'dashboard.widgets' as const,\n order,\n colSpan,\n }) as DashboardTarget;\n return defineExtension({ ...stripUndefined(rest), targets: [target] });\n}\n\nexport function multiSlotExtension(ext: UIExtensionDef): UIExtensionDef {\n return defineExtension(ext);\n}\n"],"mappings":";AAoEA,SAAS,eAAiC,KAAW;AACjD,QAAM,SAAS,CAAC;AAChB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,GAAG;AACtC,QAAI,MAAM,OAAW,QAAO,CAAC,IAAI;AAAA,EACrC;AACA,SAAO;AACX;AAIO,SAAS,gBAAgB,KAAqC;AACjE,SAAO,eAAe;AAAA,IAClB,GAAG;AAAA,IACH,SAAS,IAAI,QAAQ,IAAI,CAAC,WAAW,eAAe,MAAM,CAAC;AAAA,EAC/D,CAAC;AACL;AAEO,SAAS,aAAa,KAWV;AACf,QAAM,EAAE,MAAM,OAAO,oBAAoB,QAAQ,GAAG,KAAK,IAAI;AAC7D,QAAM,SAAoB,eAAe;AAAA,IACrC,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACJ,CAAC;AACD,SAAO,gBAAgB,EAAE,GAAG,eAAe,IAAI,GAAG,SAAS,CAAC,MAAM,GAAG,GAAI,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC,EAAG,CAAC;AAC9G;AAEO,SAAS,eAAe,KASZ;AACf,QAAM,EAAE,MAAM,OAAO,QAAQ,GAAG,KAAK,IAAI;AACzC,QAAM,SAAsB,eAAe;AAAA,IACvC,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACJ,CAAC;AACD,SAAO,gBAAgB,EAAE,GAAG,eAAe,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;AACzE;AAEO,SAAS,kBAAkB,KASf;AACf,QAAM,EAAE,OAAO,YAAY,GAAG,KAAK,IAAI;AACvC,QAAM,SAAyB,eAAe;AAAA,IAC1C,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACJ,CAAC;AACD,SAAO,gBAAgB,EAAE,GAAG,eAAe,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;AACzE;AAEO,SAAS,mBAAmB,KAQhB;AACf,QAAM,EAAE,OAAO,SAAS,GAAG,KAAK,IAAI;AACpC,QAAM,SAA0B,eAAe;AAAA,IAC3C,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACJ,CAAC;AACD,SAAO,gBAAgB,EAAE,GAAG,eAAe,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;AACzE;AAEO,SAAS,mBAAmB,KAAqC;AACpE,SAAO,gBAAgB,GAAG;AAC9B;","names":[]}
@@ -0,0 +1,156 @@
1
+ // src/trpc.ts
2
+ import { initTRPC, TRPCError } from "@trpc/server";
3
+ var t = initTRPC.context().meta().create();
4
+ var ANONYMOUS_ROLE = "anonymous";
5
+ function allowsAnonymousAccess(meta) {
6
+ if (!meta || typeof meta !== "object") return false;
7
+ const metaRecord = meta;
8
+ const permission = metaRecord["permission"];
9
+ if (permission && typeof permission === "object") {
10
+ const permissionRecord = permission;
11
+ if (permissionRecord["anonymous"] === true) return true;
12
+ }
13
+ if (metaRecord["anonymous"] === true) return true;
14
+ const access = metaRecord["access"];
15
+ if (access === "anonymous") return true;
16
+ if (access && typeof access === "object") {
17
+ const accessRecord = access;
18
+ return accessRecord["anonymous"] === true || accessRecord["allowAnonymous"] === true || accessRecord["mode"] === "anonymous";
19
+ }
20
+ return false;
21
+ }
22
+ function injectAnonymousRole(target) {
23
+ const roles = Array.isArray(target["userRoles"]) ? [...target["userRoles"]] : [];
24
+ if (!roles.includes(ANONYMOUS_ROLE)) {
25
+ roles.push(ANONYMOUS_ROLE);
26
+ }
27
+ target["userRoles"] = roles;
28
+ if (!target["userRole"]) {
29
+ target["userRole"] = ANONYMOUS_ROLE;
30
+ }
31
+ }
32
+ function isTrustedSystemContext(ctxRecord) {
33
+ if (ctxRecord["isSystemContext"] === true || ctxRecord["actorType"] === "system") {
34
+ return true;
35
+ }
36
+ if (ctxRecord["invoker"] === "scheduler") {
37
+ return true;
38
+ }
39
+ const principal = ctxRecord["principal"];
40
+ return principal !== null && typeof principal === "object" && principal["kind"] === "system";
41
+ }
42
+ var pluginProcedureBase = t.procedure.use(async (opts) => {
43
+ const ctxRecord = opts.ctx ?? {};
44
+ const shouldEnforcePluginAccess = ctxRecord["__enforcePluginAccess"] === true;
45
+ const isAnonymousRequest = !ctxRecord["userId"];
46
+ if (shouldEnforcePluginAccess && isAnonymousRequest && !isTrustedSystemContext(ctxRecord)) {
47
+ if (!allowsAnonymousAccess(opts.meta)) {
48
+ throw new TRPCError({
49
+ code: "UNAUTHORIZED",
50
+ message: "Authentication required"
51
+ });
52
+ }
53
+ injectAnonymousRole(ctxRecord);
54
+ const requestContextRef = ctxRecord["__requestContextRef"];
55
+ if (requestContextRef && typeof requestContextRef === "object") {
56
+ injectAnonymousRole(requestContextRef);
57
+ }
58
+ }
59
+ const pluginProcedureMiddlewares = opts.ctx?.["__pluginProcedureMiddlewares"] ?? [];
60
+ const run = (index, accumulatedOverrides) => {
61
+ if (index >= pluginProcedureMiddlewares.length) {
62
+ return opts.next(accumulatedOverrides);
63
+ }
64
+ const middleware = pluginProcedureMiddlewares[index];
65
+ return middleware({
66
+ ...opts,
67
+ ...accumulatedOverrides,
68
+ next: (nextOverrides) => run(index + 1, {
69
+ ...accumulatedOverrides,
70
+ ...nextOverrides ?? {}
71
+ })
72
+ });
73
+ };
74
+ return run(0, {});
75
+ });
76
+ var pluginRouter = t.router;
77
+ var pluginProcedure = pluginProcedureBase;
78
+ var defaultPermissions = {
79
+ can: async () => false,
80
+ require: async () => {
81
+ throw new Error("Permission capability not available");
82
+ },
83
+ hasDeclared: () => false
84
+ };
85
+ var defaultSettings = {
86
+ get: async () => null,
87
+ has: async () => false,
88
+ set: async () => {
89
+ throw new Error("Settings capability not available");
90
+ },
91
+ delete: async () => {
92
+ throw new Error("Settings capability not available");
93
+ },
94
+ list: async () => [],
95
+ isFeatureEnabled: async () => false
96
+ };
97
+ var defaultDb = new Proxy({}, {
98
+ get() {
99
+ throw new Error("Database capability not available in this standalone plugin context");
100
+ }
101
+ });
102
+ function createPluginContext(partial) {
103
+ return {
104
+ pluginId: partial.pluginId,
105
+ organizationId: partial.organizationId,
106
+ originalOrganizationId: partial.originalOrganizationId,
107
+ userId: partial.userId,
108
+ user: partial.user,
109
+ requestId: partial.requestId,
110
+ userRole: partial.userRole,
111
+ userRoles: partial.userRoles,
112
+ currentTeamId: partial.currentTeamId,
113
+ locale: partial.locale,
114
+ timezone: partial.timezone,
115
+ clientTimeZone: partial.clientTimeZone,
116
+ resolveDateRange: partial.resolveDateRange,
117
+ actorType: partial.actorType,
118
+ apiTokenId: partial.apiTokenId,
119
+ apiTokenScopes: partial.apiTokenScopes,
120
+ isSystemContext: partial.isSystemContext,
121
+ principal: partial.principal,
122
+ invoker: partial.invoker,
123
+ logger: partial.logger ?? {
124
+ info: (msg, meta) => console.log(`[${partial.pluginId}]`, msg, meta),
125
+ warn: (msg, meta) => console.warn(`[${partial.pluginId}]`, msg, meta),
126
+ error: (msg, meta) => console.error(`[${partial.pluginId}]`, msg, meta),
127
+ debug: (msg, meta) => console.debug(`[${partial.pluginId}]`, msg, meta)
128
+ },
129
+ permissions: partial.permissions ?? defaultPermissions,
130
+ plugins: partial.plugins,
131
+ db: partial.db ?? defaultDb,
132
+ organizationProvisioning: partial.organizationProvisioning,
133
+ tx: partial.tx,
134
+ settings: partial.settings ?? defaultSettings,
135
+ currency: partial.currency,
136
+ hooks: partial.hooks,
137
+ metrics: partial.metrics,
138
+ trace: partial.trace,
139
+ media: partial.media,
140
+ storage: partial.storage,
141
+ notifications: partial.notifications,
142
+ queue: partial.queue,
143
+ usage: partial.usage,
144
+ entityExtensions: partial.entityExtensions,
145
+ crudExtensions: partial.crudExtensions,
146
+ ai: partial.ai,
147
+ aiRuntime: partial.aiRuntime
148
+ };
149
+ }
150
+
151
+ export {
152
+ pluginRouter,
153
+ pluginProcedure,
154
+ createPluginContext
155
+ };
156
+ //# sourceMappingURL=chunk-O4AYK3YP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/trpc.ts"],"sourcesContent":["import { initTRPC, TRPCError } from \"@trpc/server\";\nimport type { PluginContext, PluginPermissionCapability, PluginScopedDb, PluginSettingsCapability } from \"./types\";\n\n/**\n * tRPC builders for plugins\n *\n * Plugins use these to define their API routes, just like a normal tRPC project.\n */\nconst t = initTRPC.context<PluginContext>().meta<Record<string, unknown>>().create();\n\nconst ANONYMOUS_ROLE = \"anonymous\";\n\nfunction allowsAnonymousAccess(meta: unknown): boolean {\n if (!meta || typeof meta !== \"object\") return false;\n\n const metaRecord = meta as Record<string, unknown>;\n const permission = metaRecord[\"permission\"];\n if (permission && typeof permission === \"object\") {\n const permissionRecord = permission as Record<string, unknown>;\n if (permissionRecord[\"anonymous\"] === true) return true;\n }\n\n if (metaRecord[\"anonymous\"] === true) return true;\n\n const access = metaRecord[\"access\"];\n if (access === \"anonymous\") return true;\n\n if (access && typeof access === \"object\") {\n const accessRecord = access as Record<string, unknown>;\n return (\n accessRecord[\"anonymous\"] === true ||\n accessRecord[\"allowAnonymous\"] === true ||\n accessRecord[\"mode\"] === \"anonymous\"\n );\n }\n\n return false;\n}\n\nfunction injectAnonymousRole(target: Record<string, unknown>) {\n const roles = Array.isArray(target[\"userRoles\"]) ? [...(target[\"userRoles\"] as string[])] : [];\n if (!roles.includes(ANONYMOUS_ROLE)) {\n roles.push(ANONYMOUS_ROLE);\n }\n target[\"userRoles\"] = roles;\n if (!target[\"userRole\"]) {\n target[\"userRole\"] = ANONYMOUS_ROLE;\n }\n}\n\nfunction isTrustedSystemContext(ctxRecord: Record<string, unknown>): boolean {\n if (ctxRecord[\"isSystemContext\"] === true || ctxRecord[\"actorType\"] === \"system\") {\n return true;\n }\n\n if (ctxRecord[\"invoker\"] === \"scheduler\") {\n return true;\n }\n\n const principal = ctxRecord[\"principal\"];\n return (\n principal !== null &&\n typeof principal === \"object\" &&\n (principal as Record<string, unknown>)[\"kind\"] === \"system\"\n );\n}\n\ntype PluginProcedureMiddleware = (opts: any) => Promise<any>;\n\nconst pluginProcedureBase = t.procedure.use(async (opts) => {\n const ctxRecord = (opts.ctx as Record<string, unknown> | undefined) ?? {};\n const shouldEnforcePluginAccess = ctxRecord[\"__enforcePluginAccess\"] === true;\n const isAnonymousRequest = !ctxRecord[\"userId\"];\n\n if (shouldEnforcePluginAccess && isAnonymousRequest && !isTrustedSystemContext(ctxRecord)) {\n if (!allowsAnonymousAccess(opts.meta)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Authentication required\",\n });\n }\n\n injectAnonymousRole(ctxRecord);\n\n const requestContextRef = ctxRecord[\"__requestContextRef\"];\n if (requestContextRef && typeof requestContextRef === \"object\") {\n injectAnonymousRole(requestContextRef as Record<string, unknown>);\n }\n }\n\n const pluginProcedureMiddlewares = ((opts.ctx as Record<string, unknown> | undefined)?.[\n \"__pluginProcedureMiddlewares\"\n ] ?? []) as PluginProcedureMiddleware[];\n\n const run = (index: number, accumulatedOverrides: Record<string, unknown>) => {\n if (index >= pluginProcedureMiddlewares.length) {\n return opts.next(accumulatedOverrides as any);\n }\n\n const middleware = pluginProcedureMiddlewares[index]!;\n return middleware({\n ...opts,\n ...accumulatedOverrides,\n next: (nextOverrides?: Record<string, unknown>) =>\n run(index + 1, {\n ...accumulatedOverrides,\n ...(nextOverrides ?? {}),\n }),\n });\n };\n\n return run(0, {});\n});\n\n/**\n * Plugin router builder\n *\n * @example\n * ```ts\n * import { pluginRouter, pluginProcedure } from '@wordrhyme/plugin';\n *\n * export const router = pluginRouter({\n * hello: pluginProcedure.query(() => 'Hello from plugin!'),\n * });\n * ```\n */\nexport const pluginRouter = t.router;\n\n/**\n * Plugin procedure builder (with context)\n *\n * Use this to define procedures that have access to PluginContext.\n */\nexport const pluginProcedure = pluginProcedureBase;\n\n/**\n * Default no-op permission capability (for standalone plugin development)\n */\nconst defaultPermissions: PluginPermissionCapability = {\n can: async () => false,\n require: async () => {\n throw new Error(\"Permission capability not available\");\n },\n hasDeclared: () => false,\n};\n\n/**\n * Default no-op settings capability (for standalone plugin development)\n */\nconst defaultSettings: PluginSettingsCapability = {\n get: async () => null,\n has: async () => false,\n set: async () => {\n throw new Error(\"Settings capability not available\");\n },\n delete: async () => {\n throw new Error(\"Settings capability not available\");\n },\n list: async () => [],\n isFeatureEnabled: async () => false,\n};\n\nconst defaultDb = new Proxy({} as PluginScopedDb, {\n get() {\n throw new Error(\"Database capability not available in this standalone plugin context\");\n },\n});\n\n/**\n * Create plugin context (used by Core to inject context)\n *\n * This is called by PluginManager when invoking plugin handlers.\n */\nexport function createPluginContext(partial: Partial<PluginContext> & { pluginId: string }): PluginContext {\n return {\n pluginId: partial.pluginId,\n organizationId: partial.organizationId,\n originalOrganizationId: partial.originalOrganizationId,\n userId: partial.userId,\n user: partial.user,\n requestId: partial.requestId,\n userRole: partial.userRole,\n userRoles: partial.userRoles,\n currentTeamId: partial.currentTeamId,\n locale: partial.locale,\n timezone: partial.timezone,\n clientTimeZone: partial.clientTimeZone,\n resolveDateRange: partial.resolveDateRange,\n actorType: partial.actorType,\n apiTokenId: partial.apiTokenId,\n apiTokenScopes: partial.apiTokenScopes,\n isSystemContext: partial.isSystemContext,\n principal: partial.principal,\n invoker: partial.invoker,\n logger: partial.logger ?? {\n info: (msg, meta) => console.log(`[${partial.pluginId}]`, msg, meta),\n warn: (msg, meta) => console.warn(`[${partial.pluginId}]`, msg, meta),\n error: (msg, meta) => console.error(`[${partial.pluginId}]`, msg, meta),\n debug: (msg, meta) => console.debug(`[${partial.pluginId}]`, msg, meta),\n },\n permissions: partial.permissions ?? defaultPermissions,\n plugins: partial.plugins,\n db: partial.db ?? defaultDb,\n organizationProvisioning: partial.organizationProvisioning,\n tx: partial.tx,\n settings: partial.settings ?? defaultSettings,\n currency: partial.currency,\n hooks: partial.hooks,\n metrics: partial.metrics,\n trace: partial.trace,\n media: partial.media,\n storage: partial.storage,\n notifications: partial.notifications,\n queue: partial.queue,\n usage: partial.usage,\n entityExtensions: partial.entityExtensions,\n crudExtensions: partial.crudExtensions,\n ai: partial.ai,\n aiRuntime: partial.aiRuntime,\n };\n}\n\n// Re-export tRPC types for convenience\nexport type { inferRouterInputs, inferRouterOutputs } from \"@trpc/server\";\n"],"mappings":"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","names":[]}
@@ -0,0 +1,37 @@
1
+ // src/entity-extensions.ts
2
+ var EXTENSION_PROJECT_SAVE_HOOK_ID = "extension.project.save";
3
+ var ENTITY_EXTENSION_VALUES_SAVE_HOOK_ID = "entity.extension.values.save";
4
+ function registerSaver(ctx, handler, options) {
5
+ if (!ctx.hooks) {
6
+ throw new Error("Entity extension value saver requires the hooks capability");
7
+ }
8
+ return ctx.hooks.on(
9
+ EXTENSION_PROJECT_SAVE_HOOK_ID,
10
+ async (payload, context) => {
11
+ if (payload.ownerPluginId !== ctx.pluginId) {
12
+ return payload;
13
+ }
14
+ const result = await handler(payload, context);
15
+ return {
16
+ ...payload,
17
+ ...result,
18
+ storedByPluginId: ctx.pluginId
19
+ };
20
+ },
21
+ options
22
+ );
23
+ }
24
+ var entityExtensions = {
25
+ registerSaver
26
+ };
27
+ function registerEntityExtensionValueSaver(ctx, handler, options) {
28
+ return registerSaver(ctx, handler, options);
29
+ }
30
+
31
+ export {
32
+ EXTENSION_PROJECT_SAVE_HOOK_ID,
33
+ ENTITY_EXTENSION_VALUES_SAVE_HOOK_ID,
34
+ entityExtensions,
35
+ registerEntityExtensionValueSaver
36
+ };
37
+ //# sourceMappingURL=chunk-UGMYO6AU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/entity-extensions.ts"],"sourcesContent":["import type { EntityExtensionField, EntityExtensionFieldType } from './manifest';\nimport type {\n HookContext,\n HookHandlerOptions,\n PluginContext,\n} from './types';\n\n/**\n * Projection customization hook for entity extension values.\n *\n * Advanced plugins can listen to this hook to customize the projection that the\n * framework persists. Normal plugins do not need to listen to it.\n */\nexport const EXTENSION_PROJECT_SAVE_HOOK_ID = 'extension.project.save';\n/** @deprecated Use EXTENSION_PROJECT_SAVE_HOOK_ID / \"extension.project.save\". */\nexport const ENTITY_EXTENSION_VALUES_SAVE_HOOK_ID = 'entity.extension.values.save';\n\nexport interface EntityExtensionValueSavePayload {\n ownerPluginId: string;\n organizationId: string;\n /** Global extension target id, e.g. \"com.example.shop.stores\". */\n targetId: string;\n entityId: string;\n values: Record<string, unknown>;\n fields: Record<string, EntityExtensionField & { type: EntityExtensionFieldType }>;\n projections?: EntityExtensionProjectionValue[];\n storedByPluginId?: string;\n}\n\nexport interface EntityExtensionProjectionValue {\n pluginId: string;\n field: string;\n type: EntityExtensionFieldType;\n value: unknown;\n display: string | null;\n searchText?: string | null;\n refEntity: string | null;\n refId: string | null;\n}\n\nexport interface EntityExtensionValueSaveResult {\n projections?: EntityExtensionProjectionValue[];\n storedByPluginId?: string;\n}\n\nexport type EntityExtensionValueSaveHandler = (\n payload: EntityExtensionValueSavePayload,\n context: HookContext,\n) => Promise<EntityExtensionValueSaveResult | undefined> | EntityExtensionValueSaveResult | undefined;\n\n/**\n * @deprecated Use `ctx.hooks.on(\"extension.project.save\", handler)`.\n */\nexport function registerSaver(\n ctx: Pick<PluginContext, 'pluginId' | 'hooks'>,\n handler: EntityExtensionValueSaveHandler,\n options?: HookHandlerOptions,\n): () => void {\n if (!ctx.hooks) {\n throw new Error('Entity extension value saver requires the hooks capability');\n }\n\n return ctx.hooks.on(\n EXTENSION_PROJECT_SAVE_HOOK_ID,\n async (payload: EntityExtensionValueSavePayload, context) => {\n if (payload.ownerPluginId !== ctx.pluginId) {\n return payload;\n }\n\n const result = await handler(payload, context);\n return {\n ...payload,\n ...result,\n storedByPluginId: ctx.pluginId,\n };\n },\n options,\n );\n}\n\n/**\n * @deprecated Use `ctx.hooks.on(\"extension.project.save\", handler)`.\n */\nexport const entityExtensions = {\n registerSaver,\n};\n\n/**\n * @deprecated Use `ctx.hooks.on(\"extension.project.save\", handler)`.\n */\nexport function registerEntityExtensionValueSaver(\n ctx: Pick<PluginContext, 'pluginId' | 'hooks'>,\n handler: EntityExtensionValueSaveHandler,\n options?: HookHandlerOptions,\n): () => void {\n return registerSaver(ctx, handler, options);\n}\n"],"mappings":";AAaO,IAAM,iCAAiC;AAEvC,IAAM,uCAAuC;AAsC7C,SAAS,cACZ,KACA,SACA,SACU;AACV,MAAI,CAAC,IAAI,OAAO;AACZ,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAChF;AAEA,SAAO,IAAI,MAAM;AAAA,IACb;AAAA,IACA,OAAO,SAA0C,YAAY;AACzD,UAAI,QAAQ,kBAAkB,IAAI,UAAU;AACxC,eAAO;AAAA,MACX;AAEA,YAAM,SAAS,MAAM,QAAQ,SAAS,OAAO;AAC7C,aAAO;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,kBAAkB,IAAI;AAAA,MAC1B;AAAA,IACJ;AAAA,IACA;AAAA,EACJ;AACJ;AAKO,IAAM,mBAAmB;AAAA,EAC5B;AACJ;AAKO,SAAS,kCACZ,KACA,SACA,SACU;AACV,SAAO,cAAc,KAAK,SAAS,OAAO;AAC9C;","names":[]}