@riverbankcms/sdk 0.7.2 → 0.7.3
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/README.md +54 -0
- package/dist/client/bookings.d.mts +2 -0
- package/dist/client/bookings.d.ts +2 -0
- package/dist/client/bookings.js +2956 -104
- package/dist/client/bookings.js.map +1 -1
- package/dist/client/bookings.mjs +2929 -70
- package/dist/client/bookings.mjs.map +1 -1
- package/dist/client/client.d.mts +2 -2
- package/dist/client/client.d.ts +2 -2
- package/dist/client/client.js +80 -11
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +87 -11
- package/dist/client/client.mjs.map +1 -1
- package/dist/client/hooks.d.mts +2 -2
- package/dist/client/hooks.d.ts +2 -2
- package/dist/client/rendering/client.js +3070 -259
- package/dist/client/rendering/client.js.map +1 -1
- package/dist/client/rendering/client.mjs +3212 -395
- package/dist/client/rendering/client.mjs.map +1 -1
- package/dist/client/spam-protection.d.mts +55 -0
- package/dist/client/spam-protection.d.ts +55 -0
- package/dist/client/spam-protection.js +2915 -0
- package/dist/client/spam-protection.js.map +1 -0
- package/dist/client/spam-protection.mjs +2893 -0
- package/dist/client/spam-protection.mjs.map +1 -0
- package/dist/client/{usePage-Db9kzA41.d.ts → usePage-BYmJCCm1.d.ts} +14 -2
- package/dist/client/{usePage-C9tJpuKa.d.mts → usePage-DZtrWajy.d.mts} +14 -2
- package/dist/server/{Layout-Ce7PU9I5.d.ts → Layout-Yluyb6sK.d.ts} +1 -1
- package/dist/server/{Layout-WllR8Zug.d.mts → Layout-qWLdVm5-.d.mts} +1 -1
- package/dist/server/chunk-2IZ6S225.js +122 -0
- package/dist/server/chunk-2IZ6S225.js.map +1 -0
- package/dist/server/chunk-4CV4JOE5.js +27 -0
- package/dist/server/chunk-4CV4JOE5.js.map +1 -0
- package/dist/server/{chunk-AET56TQX.mjs → chunk-5LRR64Y6.mjs} +32 -5
- package/dist/server/chunk-5LRR64Y6.mjs.map +1 -0
- package/dist/server/{chunk-VODFQMUW.js → chunk-NBTRDLCM.js} +32 -5
- package/dist/server/chunk-NBTRDLCM.js.map +1 -0
- package/dist/server/chunk-NFEGQTCC.mjs +27 -0
- package/dist/server/{chunk-5JT452F2.mjs → chunk-NFQLH5IA.mjs} +340 -19
- package/dist/server/chunk-NFQLH5IA.mjs.map +1 -0
- package/dist/server/chunk-PPHZV6YD.mjs +122 -0
- package/dist/server/chunk-PPHZV6YD.mjs.map +1 -0
- package/dist/server/{chunk-HMENX4Y7.js → chunk-VLXTNB2C.js} +370 -49
- package/dist/server/chunk-VLXTNB2C.js.map +1 -0
- package/dist/server/{components-RPzRQve6.d.mts → components-DNHfSCML.d.mts} +3 -3
- package/dist/server/{components--LT61IKp.d.ts → components-Di5ME6He.d.ts} +3 -3
- package/dist/server/components.d.mts +5 -5
- package/dist/server/components.d.ts +5 -5
- package/dist/server/components.js +1 -0
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +1 -0
- package/dist/server/config-validation.js +1 -0
- package/dist/server/config-validation.js.map +1 -1
- package/dist/server/config-validation.mjs +1 -0
- package/dist/server/config.js +1 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +1 -0
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/data.d.mts +2 -2
- package/dist/server/data.d.ts +2 -2
- package/dist/server/data.js +1 -0
- package/dist/server/data.js.map +1 -1
- package/dist/server/data.mjs +1 -0
- package/dist/server/env.d.mts +91 -5
- package/dist/server/env.d.ts +91 -5
- package/dist/server/env.js +9 -2
- package/dist/server/env.js.map +1 -1
- package/dist/server/env.mjs +8 -1
- package/dist/server/{index-BL66CU6d.d.mts → index--Oyunk_B.d.mts} +2 -2
- package/dist/server/{index-CJk9iQQW.d.ts → index-C9Ra8dza.d.ts} +2 -2
- package/dist/server/{index-Bkva0WAj.d.mts → index-Clm3skz_.d.mts} +1 -1
- package/dist/server/{index-CSBWKA3r.d.ts → index-DLvNddi-.d.ts} +1 -1
- package/dist/server/index.d.mts +215 -4
- package/dist/server/index.d.ts +215 -4
- package/dist/server/index.js +301 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +301 -3
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/{loadContent-CXUWMuzY.d.ts → loadContent-D7LQwI0o.d.ts} +3 -3
- package/dist/server/{loadContent-F_tAS0Nl.d.mts → loadContent-DVfuBLiZ.d.mts} +3 -3
- package/dist/server/{loadPage-6I7F6GRF.js → loadPage-AXNAERDS.js} +2 -1
- package/dist/server/loadPage-AXNAERDS.js.map +1 -0
- package/dist/server/{loadPage-i2r-X5b9.d.ts → loadPage-BmYJCe_V.d.ts} +2 -2
- package/dist/server/{loadPage-CxlYLe5K.d.mts → loadPage-BucnLHmE.d.mts} +2 -2
- package/dist/server/{loadPage-JI2SML4M.mjs → loadPage-XR7ORQ2E.mjs} +2 -1
- package/dist/server/loadPage-XR7ORQ2E.mjs.map +1 -0
- package/dist/server/metadata.d.mts +4 -4
- package/dist/server/metadata.d.ts +4 -4
- package/dist/server/metadata.js +1 -0
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/metadata.mjs +1 -0
- package/dist/server/navigation.d.mts +2 -2
- package/dist/server/navigation.d.ts +2 -2
- package/dist/server/navigation.js +1 -0
- package/dist/server/navigation.js.map +1 -1
- package/dist/server/navigation.mjs +1 -0
- package/dist/server/next/revalidate.js +5 -4
- package/dist/server/next/revalidate.js.map +1 -1
- package/dist/server/next/revalidate.mjs +3 -2
- package/dist/server/next/revalidate.mjs.map +1 -1
- package/dist/server/next/tags.d.mts +3 -0
- package/dist/server/next/tags.d.ts +3 -0
- package/dist/server/next/tags.js +3 -1
- package/dist/server/next/tags.js.map +1 -1
- package/dist/server/next/tags.mjs +2 -0
- package/dist/server/next/tags.mjs.map +1 -1
- package/dist/server/next.d.mts +5 -5
- package/dist/server/next.d.ts +5 -5
- package/dist/server/next.js +5 -4
- package/dist/server/next.js.map +1 -1
- package/dist/server/next.mjs +3 -2
- package/dist/server/next.mjs.map +1 -1
- package/dist/server/rendering/server.d.mts +4 -4
- package/dist/server/rendering/server.d.ts +4 -4
- package/dist/server/rendering/server.js +1 -0
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +1 -0
- package/dist/server/rendering.d.mts +7 -7
- package/dist/server/rendering.d.ts +7 -7
- package/dist/server/rendering.js +1 -0
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +1 -0
- package/dist/server/routing.d.mts +3 -3
- package/dist/server/routing.d.ts +3 -3
- package/dist/server/routing.js +4 -2
- package/dist/server/routing.js.map +1 -1
- package/dist/server/routing.mjs +3 -1
- package/dist/server/routing.mjs.map +1 -1
- package/dist/server/server.d.mts +5 -5
- package/dist/server/server.d.ts +5 -5
- package/dist/server/server.js +3 -2
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.mjs +2 -1
- package/dist/server/theme-bridge.js +1 -0
- package/dist/server/theme-bridge.js.map +1 -1
- package/dist/server/theme-bridge.mjs +1 -0
- package/dist/server/theme-bridge.mjs.map +1 -1
- package/dist/server/theme.js +3 -1
- package/dist/server/theme.js.map +1 -1
- package/dist/server/theme.mjs +2 -0
- package/dist/server/theme.mjs.map +1 -1
- package/dist/server/{types-DnkRh0UL.d.ts → types-BRQyLrQU.d.ts} +14 -2
- package/dist/server/{types-Dsu9wsUh.d.mts → types-BSV6Vc-P.d.mts} +2 -2
- package/dist/server/{types-MF2AWoKv.d.mts → types-C-LShyIg.d.mts} +14 -2
- package/dist/server/{types-CVykEqXN.d.ts → types-Dt98DeYa.d.ts} +2 -2
- package/dist/server/webhooks.d.mts +8 -2
- package/dist/server/webhooks.d.ts +8 -2
- package/dist/server/webhooks.js +3 -2
- package/dist/server/webhooks.js.map +1 -1
- package/dist/server/webhooks.mjs +2 -1
- package/package.json +7 -1
- package/dist/client/resolver-BhueZVxZ.d.mts +0 -61
- package/dist/client/resolver-BhueZVxZ.d.ts +0 -61
- package/dist/client/usePage--fGlyrgj.d.mts +0 -6439
- package/dist/client/usePage-BBcFCxOU.d.ts +0 -6297
- package/dist/client/usePage-BC8Q2E3t.d.mts +0 -6431
- package/dist/client/usePage-BTPnCuWC.d.mts +0 -6511
- package/dist/client/usePage-BXjk8BhD.d.mts +0 -6704
- package/dist/client/usePage-BafOS9UT.d.mts +0 -6512
- package/dist/client/usePage-BcjWPXvh.d.mts +0 -6388
- package/dist/client/usePage-BiOReg0_.d.ts +0 -6704
- package/dist/client/usePage-Bnx-kA6x.d.mts +0 -6670
- package/dist/client/usePage-BvKAa3Zw.d.mts +0 -366
- package/dist/client/usePage-BvKAa3Zw.d.ts +0 -366
- package/dist/client/usePage-BydHcMYB.d.mts +0 -6297
- package/dist/client/usePage-C3ZKNwY7.d.mts +0 -6393
- package/dist/client/usePage-CE7X5NcN.d.ts +0 -6439
- package/dist/client/usePage-CHEybPMD.d.ts +0 -6429
- package/dist/client/usePage-CrKw1H6Y.d.ts +0 -6338
- package/dist/client/usePage-CyYpOJud.d.ts +0 -6388
- package/dist/client/usePage-D4fxZbRR.d.mts +0 -6429
- package/dist/client/usePage-DMI8ImsU.d.mts +0 -6338
- package/dist/client/usePage-DoPI6b8V.d.ts +0 -6511
- package/dist/client/usePage-DpRNZUtP.d.ts +0 -6431
- package/dist/client/usePage-QNWArrVO.d.ts +0 -6670
- package/dist/client/usePage-fBgPB6Oq.d.ts +0 -6512
- package/dist/client/usePage-gpVaeWDy.d.ts +0 -6393
- package/dist/server/chunk-5JT452F2.mjs.map +0 -1
- package/dist/server/chunk-AET56TQX.mjs.map +0 -1
- package/dist/server/chunk-HMENX4Y7.js.map +0 -1
- package/dist/server/chunk-LQUKXIW7.mjs +0 -13
- package/dist/server/chunk-LQUKXIW7.mjs.map +0 -1
- package/dist/server/chunk-VODFQMUW.js.map +0 -1
- package/dist/server/chunk-WYNEYDXO.js +0 -13
- package/dist/server/chunk-WYNEYDXO.js.map +0 -1
- package/dist/server/loadPage-6I7F6GRF.js.map +0 -1
- /package/dist/server/{loadPage-JI2SML4M.mjs.map → chunk-NFEGQTCC.mjs.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/config.js","../../src/config/typed-entries.ts","../../src/config/index.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACA;AC+KO,SAAS,sBAAA,CAGd,MAAA,EAAwD;AACxD,EAAA,OAAO,MAAA;AACT;AAwDO,SAAS,WAAA,CAId,WAAA,EACA,KAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,WAAA,EAAa,WAAA,CAAY;AAAA,EAC3B,CAAA;AACF;AA2BO,IAAM,OAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpB,KAAA,CAAA,EAAoB;AAClB,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,CAAC,EAAE,CAAA;AAAA,EACpC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAA,CAAU,IAAA,EAA0B;AAClC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,KAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACP;AAAA,UACE,IAAA,EAAM,WAAA;AAAA,UACN,OAAA,EAAS,KAAA,EAAO,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAK,CAAC,EAAA,EAAI,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,IACF,CAAA;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,GAAA,CAAI,OAAA,EAAmC;AACrC,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA;AAAA,EAChC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAA,CAAQ,KAAA,EAA8B,IAAA,EAA0B;AAC9D,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,SAAA;AAAA,MACN,KAAA,EAAO,EAAE,MAAM,CAAA;AAAA,MACf,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAK,CAAC;AAAA,IAClC,CAAA;AAAA,EACF;AACF,CAAA;AD1QA;AACA;AEkCO,SAAS,YAAA,CAAa,MAAA,EAAkD;AAC7E,EAAA,OAAO,MAAA;AACT;AAuCO,SAAS,mBAAA,CAAoB,MAAA,EAAsC;AACxE,EAAA,OAAO,MAAA;AACT;AFtEA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,0/DAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/config.js","sourcesContent":[null,"/**\n * Type-Safe Content Entries\n *\n * This module provides type-safe helpers for defining content types and entries\n * in SDK site configurations. When used with `as const`, TypeScript can infer\n * the exact shape of entry data from the content type's field definitions.\n *\n * @example\n * ```typescript\n * import { defineTypedContentType, createEntry, tiptap } from '@riverbankcms/sdk/config';\n *\n * // Define content type with `as const` for type inference\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n *\n * // Create entry with full type safety\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * data: {\n * name: 'John Doe', // TypeScript knows this is string\n * quote: tiptap.paragraph('Great service!'), // TypeScript knows this is TipTapNode\n * },\n * });\n * ```\n */\n\nimport type {\n FieldDefinition,\n TextFieldDefinition,\n RichTextFieldDefinition,\n MediaFieldDefinition,\n BooleanFieldDefinition,\n NumberFieldDefinition,\n DateFieldDefinition,\n TimeFieldDefinition,\n DateTimeFieldDefinition,\n SlugFieldDefinition,\n UrlFieldDefinition,\n LinkFieldDefinition,\n SelectFieldDefinition,\n ReferenceFieldDefinition,\n RepeaterFieldDefinition,\n GroupFieldDefinition,\n ModalFieldDefinition,\n TabGroupFieldDefinition,\n PresetOrCustomFieldDefinition,\n ContentTypeSelectFieldDefinition,\n EntryPickerFieldDefinition,\n TipTapNode,\n Media,\n LinkValue,\n} from '@riverbankcms/blocks';\nimport type { ContentTypeConfig, EntryConfig } from './content-types';\n\n// Re-export value types for convenience\nexport type { TipTapNode, Media, LinkValue } from '@riverbankcms/blocks';\nexport type {\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from '@riverbankcms/blocks';\n\n// =============================================================================\n// Type Infrastructure\n// =============================================================================\n\n/**\n * Infers the data object shape from tabGroup tabs (flattens all tab fields).\n * TabGroup fields flatten all their tab fields into a single data object.\n */\ntype InferDataFromTabs<Tabs extends readonly { fields: readonly FieldDefinition[] }[]> =\n InferDataFromFields<Tabs[number]['fields']>;\n\n// NOTE: Polymorphic repeater type inference would require a helper like this,\n// but TypeScript's mapped types don't distribute correctly over union keys\n// when nested inside conditional types. Left as documentation for future work.\n// type PolymorphicItemData<K, IT> = K extends string\n// ? K extends keyof IT\n// ? IT[K] extends { fields: infer F extends readonly FieldDefinition[] }\n// ? { _type: K } & InferDataFromFields<F>\n// : never\n// : never\n// : never;\n\n/**\n * Maps a field definition to its TypeScript value type.\n * Uses conditional types to infer the correct type based on field.type.\n *\n * Coverage:\n * - Simple primitives: text, boolean, number\n * - Complex types: richText (TipTapNode), media (Media | null), link (LinkValue | null)\n * - Date/time: date, time, datetime (all ISO strings)\n * - String-value: slug, url, reference, presetOrCustom, contentTypeSelect\n * - Select: single (string) vs multiple (string[])\n * - Entry picker: string | null\n * - Nested: group, modal (nested InferDataFromFields)\n * - Repeater: monomorphic (array) and polymorphic (discriminated union array)\n * - TabGroup: flattened fields from all tabs\n */\nexport type FieldValueType<F extends FieldDefinition> =\n // Simple primitives - use specific field types for better inference\n F extends TextFieldDefinition ? string :\n F extends BooleanFieldDefinition ? boolean :\n F extends NumberFieldDefinition ? number :\n // Complex types\n F extends RichTextFieldDefinition ? TipTapNode :\n F extends MediaFieldDefinition ? Media | null :\n F extends LinkFieldDefinition ? LinkValue | null :\n // Date/time types (all stored as ISO strings)\n F extends DateFieldDefinition ? string :\n F extends TimeFieldDefinition ? string :\n F extends DateTimeFieldDefinition ? string :\n // String-value types\n F extends SlugFieldDefinition ? string :\n F extends UrlFieldDefinition ? string :\n F extends ReferenceFieldDefinition ? string :\n F extends PresetOrCustomFieldDefinition ? string :\n F extends ContentTypeSelectFieldDefinition ? string :\n // Select: check multiple flag first (more specific match)\n F extends SelectFieldDefinition & { multiple: true } ? string[] :\n F extends SelectFieldDefinition ? string :\n // Entry picker\n F extends EntryPickerFieldDefinition ? string | null :\n // Nested types (group, modal)\n F extends GroupFieldDefinition & { schema: { fields: infer GF } } ?\n GF extends readonly FieldDefinition[] ? InferDataFromFields<GF> : never :\n F extends ModalFieldDefinition & { schema: { fields: infer MF } } ?\n MF extends readonly FieldDefinition[] ? InferDataFromFields<MF> : never :\n // Repeater types (polymorphic first - more specific, then monomorphic)\n // TODO: Polymorphic repeaters need more complex type distribution.\n // For now, return unknown[] - the runtime data is still correct.\n F extends { type: 'repeater'; polymorphic: true } ? unknown[] :\n F extends RepeaterFieldDefinition & { schema: { fields: infer RF } } ?\n RF extends readonly FieldDefinition[] ? InferDataFromFields<RF>[] : never :\n // TabGroup (flattens all tab fields)\n F extends TabGroupFieldDefinition & { tabs: infer T } ?\n T extends readonly { fields: readonly FieldDefinition[] }[] ?\n InferDataFromTabs<T> : never :\n // Fallback for unknown types\n unknown;\n\n/**\n * Infers the data object shape from an array of field definitions.\n * Required fields are non-optional, optional fields are `| undefined`.\n *\n * @example\n * ```typescript\n * const fields = [\n * { id: 'name', type: 'text', required: true },\n * { id: 'bio', type: 'text', required: false },\n * ] as const;\n *\n * type Data = InferDataFromFields<typeof fields>;\n * // { name: string; bio: string | undefined }\n * ```\n */\nexport type InferDataFromFields<Fields extends readonly FieldDefinition[]> = {\n [F in Fields[number] as F['id']]: F extends { required: true }\n ? FieldValueType<F>\n : FieldValueType<F> | undefined;\n};\n\n// =============================================================================\n// TypedContentType\n// =============================================================================\n\n/**\n * A content type definition with preserved field types for type inference.\n * Extends ContentTypeConfig to ensure all required fields are present.\n * The generic parameters capture the literal types from `as const`.\n */\nexport interface TypedContentType<\n K extends string = string,\n F extends readonly FieldDefinition[] = readonly FieldDefinition[]\n> extends Omit<ContentTypeConfig, 'key' | 'fields'> {\n key: K;\n fields: F;\n}\n\n/**\n * Define a content type with preserved field types for type inference.\n *\n * IMPORTANT: Use `as const` on the config object to enable type inference.\n * Without `as const`, TypeScript widens literal types and inference won't work.\n *\n * @param config - The content type configuration\n * @returns The same config object with preserved types\n *\n * @example\n * ```typescript\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n * ```\n */\nexport function defineTypedContentType<\n K extends string,\n F extends readonly FieldDefinition[]\n>(config: TypedContentType<K, F>): TypedContentType<K, F> {\n return config;\n}\n\n// =============================================================================\n// TypedEntryConfig and createEntry\n// =============================================================================\n\n/**\n * Entry configuration with typed data field.\n * Used internally by createEntry to enforce type safety.\n */\nexport interface TypedEntryConfig<Data extends Record<string, unknown>> {\n /** Unique identifier for this entry. Required for SDK sync. */\n identifier: string;\n /** Title for the entry */\n title?: string;\n /** Slug for routable entries */\n slug?: string;\n /** Status: 'draft' or 'published' */\n status?: 'draft' | 'published';\n /** Summary/description */\n summary?: string;\n /** SEO meta title */\n metaTitle?: string;\n /** SEO meta description */\n metaDescription?: string;\n /** Entry data matching the content type's field definitions */\n data: Data;\n}\n\n/**\n * Create a type-safe content entry for a typed content type.\n *\n * The data field is validated against the content type's field definitions.\n * TypeScript will error if:\n * - A required field is missing\n * - A field name is misspelled\n * - A field value has the wrong type\n * - An extra field is provided (with strict mode)\n *\n * @param contentType - The typed content type definition\n * @param entry - The entry configuration with typed data\n * @returns EntryConfig compatible with SDK content configuration\n *\n * @example\n * ```typescript\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * title: 'John Doe',\n * status: 'published',\n * data: {\n * name: 'John Doe',\n * quote: tiptap.paragraph('Great service!'),\n * },\n * });\n * ```\n */\nexport function createEntry<\n K extends string,\n F extends readonly FieldDefinition[]\n>(\n contentType: TypedContentType<K, F>,\n entry: TypedEntryConfig<InferDataFromFields<F>>\n): EntryConfig {\n return {\n ...entry,\n contentType: contentType.key,\n };\n}\n\n// =============================================================================\n// TipTap Helpers\n// =============================================================================\n\n/**\n * Helpers for creating TipTap document structures.\n *\n * Use these helpers when populating richText fields to avoid manually\n * constructing the TipTap JSON structure.\n *\n * @example\n * ```typescript\n * // Simple paragraph\n * const body = tiptap.paragraph('Hello, world!');\n *\n * // Empty document\n * const emptyDoc = tiptap.empty();\n *\n * // Complex document\n * const doc = tiptap.doc([\n * tiptap.heading(1, 'Welcome'),\n * { type: 'paragraph', content: [{ type: 'text', text: 'Introduction...' }] },\n * ]);\n * ```\n */\nexport const tiptap = {\n /**\n * Create an empty TipTap document.\n *\n * @returns An empty TipTap document node\n */\n empty(): TipTapNode {\n return { type: 'doc', content: [] };\n },\n\n /**\n * Create a TipTap document with a single paragraph.\n *\n * @param text - The paragraph text content\n * @returns A TipTap document with one paragraph\n */\n paragraph(text: string): TipTapNode {\n return {\n type: 'doc',\n content: [\n {\n type: 'paragraph',\n content: text ? [{ type: 'text', text }] : [],\n },\n ],\n };\n },\n\n /**\n * Create a TipTap document with custom content nodes.\n *\n * @param content - Array of TipTap nodes to include in the document\n * @returns A TipTap document wrapping the content\n */\n doc(content: TipTapNode[]): TipTapNode {\n return { type: 'doc', content };\n },\n\n /**\n * Create a heading node.\n *\n * Note: This returns a heading node, not a document. Use with tiptap.doc()\n * to create a complete document.\n *\n * @param level - Heading level (1-6)\n * @param text - Heading text content\n * @returns A TipTap heading node\n */\n heading(level: 1 | 2 | 3 | 4 | 5 | 6, text: string): TipTapNode {\n return {\n type: 'heading',\n attrs: { level },\n content: [{ type: 'text', text }],\n };\n },\n};\n","/**\n * SDK Site Configuration\n *\n * Types and utilities for defining site-level configuration\n * that SDK sites expose to the dashboard.\n */\n\nimport type { RiverbankSiteConfig, ContentConfig } from './types';\n\n// Types\nexport type {\n RiverbankSiteConfig,\n SiteStyleConfig,\n SectionBackground,\n SectionOptionsConfig,\n ContainerOptionsConfig,\n SectionSpacing,\n ContainerMaxWidth,\n ContainerAlignment,\n SdkThemeConfig,\n SdkThemePalette,\n SdkCustomBlock,\n FieldSelectOption,\n BlockFieldConfig,\n BlockFieldOptionsMap,\n BlockFieldExtension,\n BlockFieldExtensionsMap,\n FieldDefinition,\n // Content scaffolding types\n ContentConfig,\n ContentTypeConfig,\n PageConfig,\n EntryConfig,\n BlockConfig,\n NavigationMenuConfig,\n NavigationItemConfig,\n NavigationLinkType,\n SiteSettingsConfig,\n} from './types';\n\n// Validation schemas\nexport {\n riverbankSiteConfigSchema,\n siteStyleConfigSchema,\n sectionBackgroundSchema,\n sectionSpacingSchema,\n containerMaxWidthSchema,\n containerAlignmentSchema,\n sectionOptionsSchema,\n containerOptionsSchema,\n sdkThemeConfigSchema,\n sdkThemePaletteSchema,\n sdkCustomBlockSchema,\n fieldSelectOptionSchema,\n blockFieldConfigSchema,\n blockFieldOptionsSchema,\n blockFieldExtensionSchema,\n blockFieldExtensionsSchema,\n // Content scaffolding schemas\n contentConfigSchema,\n} from './validation';\n\n// Content validation schemas for more granular use\nexport {\n contentTypeConfigSchema,\n pageConfigSchema,\n entryConfigSchema,\n navigationMenuConfigSchema,\n navigationItemConfigSchema,\n siteSettingsConfigSchema,\n blockConfigSchema,\n} from './content-validation';\n\nexport type {\n ValidatedRiverbankSiteConfig,\n ValidatedSdkCustomBlock,\n ContentConfigInput,\n ContentConfigOutput,\n} from './validation';\n\n// Block kind types (single source of truth from @riverbankcms/blocks)\nexport {\n SYSTEM_BLOCK_KINDS,\n type SystemBlockKind,\n type CustomBlockKind,\n type BlockKind,\n} from '../types';\n\n// Type-safe content entry helpers\nexport {\n defineTypedContentType,\n createEntry,\n tiptap,\n type TypedContentType,\n type TypedEntryConfig,\n type InferDataFromFields,\n type FieldValueType,\n} from './typed-entries';\n\n// Re-export value types for convenience when building entry data\nexport type {\n TipTapNode,\n Media,\n LinkValue,\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from './typed-entries';\n\n/**\n * Helper function to define a Builder site configuration with type checking.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@riverbankcms/sdk/config';\n *\n * export default defineConfig({\n * siteId: '123e4567-e89b-12d3-a456-426614174000',\n * theme: {\n * palette: {\n * primary: '#6d28d9',\n * },\n * },\n * styles: {\n * sectionBackgrounds: [\n * { id: 'primary', label: 'Purple', token: 'primary' },\n * ],\n * },\n * });\n * ```\n */\nexport function defineConfig(config: RiverbankSiteConfig): RiverbankSiteConfig {\n return config;\n}\n\n/**\n * Helper function to define content scaffolding configuration with type checking.\n *\n * This can be used to define content configuration in a separate file,\n * which is then imported into riverbank.config.ts.\n *\n * @example\n * ```typescript\n * // content.config.ts\n * import { defineContentConfig } from '@riverbankcms/sdk/config';\n *\n * export const contentConfig = defineContentConfig({\n * contentTypes: [\n * {\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'quote', type: 'richText', label: 'Quote', required: true },\n * ],\n * },\n * ],\n * pages: [\n * { identifier: 'home', title: 'Home', path: '/' },\n * ],\n * });\n *\n * // riverbank.config.ts\n * import { defineConfig } from '@riverbankcms/sdk/config';\n * import { contentConfig } from './content.config';\n *\n * export default defineConfig({\n * siteId: '...',\n * content: contentConfig,\n * });\n * ```\n */\nexport function defineContentConfig(config: ContentConfig): ContentConfig {\n return config;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/config.js","../../src/config/typed-entries.ts","../../src/config/index.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACA;AC8KO,SAAS,sBAAA,CAGd,MAAA,EAAwD;AACxD,EAAA,OAAO,MAAA;AACT;AAwDO,SAAS,WAAA,CAId,WAAA,EACA,KAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,WAAA,EAAa,WAAA,CAAY;AAAA,EAC3B,CAAA;AACF;AA2BO,IAAM,OAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpB,KAAA,CAAA,EAAoB;AAClB,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,CAAC,EAAE,CAAA;AAAA,EACpC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAA,CAAU,IAAA,EAA0B;AAClC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,KAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACP;AAAA,UACE,IAAA,EAAM,WAAA;AAAA,UACN,OAAA,EAAS,KAAA,EAAO,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAK,CAAC,EAAA,EAAI,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,IACF,CAAA;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,GAAA,CAAI,OAAA,EAAmC;AACrC,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA;AAAA,EAChC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAA,CAAQ,KAAA,EAA8B,IAAA,EAA0B;AAC9D,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,SAAA;AAAA,MACN,KAAA,EAAO,EAAE,MAAM,CAAA;AAAA,MACf,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAK,CAAC;AAAA,IAClC,CAAA;AAAA,EACF;AACF,CAAA;ADzQA;AACA;AEiCO,SAAS,YAAA,CAAa,MAAA,EAAkD;AAC7E,EAAA,OAAO,MAAA;AACT;AAuCO,SAAS,mBAAA,CAAoB,MAAA,EAAsC;AACxE,EAAA,OAAO,MAAA;AACT;AFrEA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,0/DAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/config.js","sourcesContent":[null,"/**\n * Type-Safe Content Entries\n *\n * This module provides type-safe helpers for defining content types and entries\n * in SDK site configurations. When used with `as const`, TypeScript can infer\n * the exact shape of entry data from the content type's field definitions.\n *\n * @example\n * ```typescript\n * import { defineTypedContentType, createEntry, tiptap } from '@riverbankcms/sdk/config';\n *\n * // Define content type with `as const` for type inference\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n *\n * // Create entry with full type safety\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * data: {\n * name: 'John Doe', // TypeScript knows this is string\n * quote: tiptap.paragraph('Great service!'), // TypeScript knows this is TipTapNode\n * },\n * });\n * ```\n */\n\nimport type {\n FieldDefinition,\n TextFieldDefinition,\n RichTextFieldDefinition,\n MediaFieldDefinition,\n BooleanFieldDefinition,\n NumberFieldDefinition,\n DateFieldDefinition,\n TimeFieldDefinition,\n DateTimeFieldDefinition,\n SlugFieldDefinition,\n UrlFieldDefinition,\n LinkFieldDefinition,\n SelectFieldDefinition,\n ReferenceFieldDefinition,\n RepeaterFieldDefinition,\n GroupFieldDefinition,\n ModalFieldDefinition,\n TabGroupFieldDefinition,\n PresetOrCustomFieldDefinition,\n ContentTypeSelectFieldDefinition,\n EntryPickerFieldDefinition,\n TipTapNode,\n Media,\n LinkValue,\n} from '@riverbankcms/blocks';\nimport type { ContentTypeConfig, EntryConfig } from './content-types';\n\n// Re-export value types for convenience\nexport type { TipTapNode, Media, LinkValue } from '@riverbankcms/blocks';\nexport type {\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from '@riverbankcms/blocks';\n\n// =============================================================================\n// Type Infrastructure\n// =============================================================================\n\n/**\n * Infers the data object shape from tabGroup tabs (flattens all tab fields).\n * TabGroup fields flatten all their tab fields into a single data object.\n */\ntype InferDataFromTabs<Tabs extends readonly { fields: readonly FieldDefinition[] }[]> =\n InferDataFromFields<Tabs[number]['fields']>;\n\n// NOTE: Polymorphic repeater type inference would require a helper like this,\n// but TypeScript's mapped types don't distribute correctly over union keys\n// when nested inside conditional types. Left as documentation for future work.\n// type PolymorphicItemData<K, IT> = K extends string\n// ? K extends keyof IT\n// ? IT[K] extends { fields: infer F extends readonly FieldDefinition[] }\n// ? { _type: K } & InferDataFromFields<F>\n// : never\n// : never\n// : never;\n\n/**\n * Maps a field definition to its TypeScript value type.\n * Uses conditional types to infer the correct type based on field.type.\n *\n * Coverage:\n * - Simple primitives: text, boolean, number\n * - Complex types: richText (TipTapNode), media (Media | null), link (LinkValue | null)\n * - Date/time: date, time, datetime (all ISO strings)\n * - String-value: slug, url, reference, presetOrCustom, contentTypeSelect\n * - Select: single (string) vs multiple (string[])\n * - Entry picker: string | null\n * - Nested: group, modal (nested InferDataFromFields)\n * - Repeater: monomorphic (array) and polymorphic (discriminated union array)\n * - TabGroup: flattened fields from all tabs\n */\nexport type FieldValueType<F extends FieldDefinition> =\n // Simple primitives - use specific field types for better inference\n F extends TextFieldDefinition ? string :\n F extends BooleanFieldDefinition ? boolean :\n F extends NumberFieldDefinition ? number :\n // Complex types\n F extends RichTextFieldDefinition ? TipTapNode :\n F extends MediaFieldDefinition ? Media | null :\n F extends LinkFieldDefinition ? LinkValue | null :\n // Date/time types (all stored as ISO strings)\n F extends DateFieldDefinition ? string :\n F extends TimeFieldDefinition ? string :\n F extends DateTimeFieldDefinition ? string :\n // String-value types\n F extends SlugFieldDefinition ? string :\n F extends UrlFieldDefinition ? string :\n F extends ReferenceFieldDefinition ? string :\n F extends PresetOrCustomFieldDefinition ? string :\n F extends ContentTypeSelectFieldDefinition ? string :\n // Select: check multiple flag first (more specific match)\n F extends SelectFieldDefinition & { multiple: true } ? string[] :\n F extends SelectFieldDefinition ? string :\n // Entry picker\n F extends EntryPickerFieldDefinition ? string | null :\n // Nested types (group, modal)\n F extends GroupFieldDefinition & { schema: { fields: infer GF } } ?\n GF extends readonly FieldDefinition[] ? InferDataFromFields<GF> : never :\n F extends ModalFieldDefinition & { schema: { fields: infer MF } } ?\n MF extends readonly FieldDefinition[] ? InferDataFromFields<MF> : never :\n // Repeater types (polymorphic first - more specific, then monomorphic)\n // TODO: Polymorphic repeaters need more complex type distribution.\n // For now, return unknown[] - the runtime data is still correct.\n F extends { type: 'repeater'; polymorphic: true } ? unknown[] :\n F extends RepeaterFieldDefinition & { schema: { fields: infer RF } } ?\n RF extends readonly FieldDefinition[] ? InferDataFromFields<RF>[] : never :\n // TabGroup (flattens all tab fields)\n F extends TabGroupFieldDefinition & { tabs: infer T } ?\n T extends readonly { fields: readonly FieldDefinition[] }[] ?\n InferDataFromTabs<T> : never :\n // Fallback for unknown types\n unknown;\n\n/**\n * Infers the data object shape from an array of field definitions.\n * Required fields are non-optional, optional fields are `| undefined`.\n *\n * @example\n * ```typescript\n * const fields = [\n * { id: 'name', type: 'text', required: true },\n * { id: 'bio', type: 'text', required: false },\n * ] as const;\n *\n * type Data = InferDataFromFields<typeof fields>;\n * // { name: string; bio: string | undefined }\n * ```\n */\nexport type InferDataFromFields<Fields extends readonly FieldDefinition[]> = {\n [F in Fields[number] as F['id']]: F extends { required: true }\n ? FieldValueType<F>\n : FieldValueType<F> | undefined;\n};\n\n// =============================================================================\n// TypedContentType\n// =============================================================================\n\n/**\n * A content type definition with preserved field types for type inference.\n * Extends ContentTypeConfig to ensure all required fields are present.\n * The generic parameters capture the literal types from `as const`.\n */\nexport interface TypedContentType<\n K extends string = string,\n F extends readonly FieldDefinition[] = readonly FieldDefinition[]\n> extends Omit<ContentTypeConfig, 'key' | 'fields'> {\n key: K;\n fields: F;\n}\n\n/**\n * Define a content type with preserved field types for type inference.\n *\n * IMPORTANT: Use `as const` on the config object to enable type inference.\n * Without `as const`, TypeScript widens literal types and inference won't work.\n *\n * @param config - The content type configuration\n * @returns The same config object with preserved types\n *\n * @example\n * ```typescript\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n * ```\n */\nexport function defineTypedContentType<\n K extends string,\n F extends readonly FieldDefinition[]\n>(config: TypedContentType<K, F>): TypedContentType<K, F> {\n return config;\n}\n\n// =============================================================================\n// TypedEntryConfig and createEntry\n// =============================================================================\n\n/**\n * Entry configuration with typed data field.\n * Used internally by createEntry to enforce type safety.\n */\nexport interface TypedEntryConfig<Data extends Record<string, unknown>> {\n /** Unique identifier for this entry. Required for SDK sync. */\n identifier: string;\n /** Title for the entry */\n title?: string;\n /** Slug for routable entries */\n slug?: string;\n /** Status: 'draft' or 'published' */\n status?: 'draft' | 'published';\n /** Summary/description */\n summary?: string;\n /** SEO meta title */\n metaTitle?: string;\n /** SEO meta description */\n metaDescription?: string;\n /** Entry data matching the content type's field definitions */\n data: Data;\n}\n\n/**\n * Create a type-safe content entry for a typed content type.\n *\n * The data field is validated against the content type's field definitions.\n * TypeScript will error if:\n * - A required field is missing\n * - A field name is misspelled\n * - A field value has the wrong type\n * - An extra field is provided (with strict mode)\n *\n * @param contentType - The typed content type definition\n * @param entry - The entry configuration with typed data\n * @returns EntryConfig compatible with SDK content configuration\n *\n * @example\n * ```typescript\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * title: 'John Doe',\n * status: 'published',\n * data: {\n * name: 'John Doe',\n * quote: tiptap.paragraph('Great service!'),\n * },\n * });\n * ```\n */\nexport function createEntry<\n K extends string,\n F extends readonly FieldDefinition[]\n>(\n contentType: TypedContentType<K, F>,\n entry: TypedEntryConfig<InferDataFromFields<F>>\n): EntryConfig {\n return {\n ...entry,\n contentType: contentType.key,\n };\n}\n\n// =============================================================================\n// TipTap Helpers\n// =============================================================================\n\n/**\n * Helpers for creating TipTap document structures.\n *\n * Use these helpers when populating richText fields to avoid manually\n * constructing the TipTap JSON structure.\n *\n * @example\n * ```typescript\n * // Simple paragraph\n * const body = tiptap.paragraph('Hello, world!');\n *\n * // Empty document\n * const emptyDoc = tiptap.empty();\n *\n * // Complex document\n * const doc = tiptap.doc([\n * tiptap.heading(1, 'Welcome'),\n * { type: 'paragraph', content: [{ type: 'text', text: 'Introduction...' }] },\n * ]);\n * ```\n */\nexport const tiptap = {\n /**\n * Create an empty TipTap document.\n *\n * @returns An empty TipTap document node\n */\n empty(): TipTapNode {\n return { type: 'doc', content: [] };\n },\n\n /**\n * Create a TipTap document with a single paragraph.\n *\n * @param text - The paragraph text content\n * @returns A TipTap document with one paragraph\n */\n paragraph(text: string): TipTapNode {\n return {\n type: 'doc',\n content: [\n {\n type: 'paragraph',\n content: text ? [{ type: 'text', text }] : [],\n },\n ],\n };\n },\n\n /**\n * Create a TipTap document with custom content nodes.\n *\n * @param content - Array of TipTap nodes to include in the document\n * @returns A TipTap document wrapping the content\n */\n doc(content: TipTapNode[]): TipTapNode {\n return { type: 'doc', content };\n },\n\n /**\n * Create a heading node.\n *\n * Note: This returns a heading node, not a document. Use with tiptap.doc()\n * to create a complete document.\n *\n * @param level - Heading level (1-6)\n * @param text - Heading text content\n * @returns A TipTap heading node\n */\n heading(level: 1 | 2 | 3 | 4 | 5 | 6, text: string): TipTapNode {\n return {\n type: 'heading',\n attrs: { level },\n content: [{ type: 'text', text }],\n };\n },\n};\n","/**\n * SDK Site Configuration\n *\n * Types and utilities for defining site-level configuration\n * that SDK sites expose to the dashboard.\n */\n\nimport type { RiverbankSiteConfig, ContentConfig } from './types';\n\n// Types\nexport type {\n RiverbankSiteConfig,\n SiteStyleConfig,\n SectionBackground,\n SectionOptionsConfig,\n ContainerOptionsConfig,\n SectionSpacing,\n ContainerMaxWidth,\n ContainerAlignment,\n SdkThemeConfig,\n SdkThemePalette,\n SdkCustomBlock,\n FieldSelectOption,\n BlockFieldConfig,\n BlockFieldOptionsMap,\n BlockFieldExtension,\n BlockFieldExtensionsMap,\n FieldDefinition,\n // Content scaffolding types\n ContentConfig,\n ContentTypeConfig,\n PageConfig,\n EntryConfig,\n BlockConfig,\n NavigationMenuConfig,\n NavigationItemConfig,\n NavigationLinkType,\n SiteSettingsConfig,\n} from './types';\n\n// Validation schemas\nexport {\n riverbankSiteConfigSchema,\n siteStyleConfigSchema,\n sectionBackgroundSchema,\n sectionSpacingSchema,\n containerMaxWidthSchema,\n containerAlignmentSchema,\n sectionOptionsSchema,\n containerOptionsSchema,\n sdkThemeConfigSchema,\n sdkThemePaletteSchema,\n sdkCustomBlockSchema,\n fieldSelectOptionSchema,\n blockFieldConfigSchema,\n blockFieldOptionsSchema,\n blockFieldExtensionSchema,\n blockFieldExtensionsSchema,\n // Content scaffolding schemas\n contentConfigSchema,\n} from './validation';\n\n// Content validation schemas for more granular use\nexport {\n contentTypeConfigSchema,\n pageConfigSchema,\n entryConfigSchema,\n navigationMenuConfigSchema,\n navigationItemConfigSchema,\n siteSettingsConfigSchema,\n blockConfigSchema,\n} from './content-validation';\n\nexport type {\n ValidatedRiverbankSiteConfig,\n ValidatedSdkCustomBlock,\n ContentConfigInput,\n ContentConfigOutput,\n} from './validation';\n\n// Block kind types (single source of truth from @riverbankcms/blocks)\nexport {\n SYSTEM_BLOCK_KINDS,\n type SystemBlockKind,\n type CustomBlockKind,\n type BlockKind,\n} from '../types';\n\n// Type-safe content entry helpers\nexport {\n defineTypedContentType,\n createEntry,\n tiptap,\n type TypedContentType,\n type TypedEntryConfig,\n type InferDataFromFields,\n type FieldValueType,\n} from './typed-entries';\n\n// Re-export value types for convenience when building entry data\nexport type {\n TipTapNode,\n Media,\n LinkValue,\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from './typed-entries';\n\n/**\n * Helper function to define a Builder site configuration with type checking.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@riverbankcms/sdk/config';\n *\n * export default defineConfig({\n * siteId: '123e4567-e89b-12d3-a456-426614174000',\n * theme: {\n * palette: {\n * primary: '#6d28d9',\n * },\n * },\n * styles: {\n * sectionBackgrounds: [\n * { id: 'primary', label: 'Purple', token: 'primary' },\n * ],\n * },\n * });\n * ```\n */\nexport function defineConfig(config: RiverbankSiteConfig): RiverbankSiteConfig {\n return config;\n}\n\n/**\n * Helper function to define content scaffolding configuration with type checking.\n *\n * This can be used to define content configuration in a separate file,\n * which is then imported into riverbank.config.ts.\n *\n * @example\n * ```typescript\n * // content.config.ts\n * import { defineContentConfig } from '@riverbankcms/sdk/config';\n *\n * export const contentConfig = defineContentConfig({\n * contentTypes: [\n * {\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'quote', type: 'richText', label: 'Quote', required: true },\n * ],\n * },\n * ],\n * pages: [\n * { identifier: 'home', title: 'Home', path: '/' },\n * ],\n * });\n *\n * // riverbank.config.ts\n * import { defineConfig } from '@riverbankcms/sdk/config';\n * import { contentConfig } from './content.config';\n *\n * export default defineConfig({\n * siteId: '...',\n * content: contentConfig,\n * });\n * ```\n */\nexport function defineContentConfig(config: ContentConfig): ContentConfig {\n return config;\n}\n"]}
|
package/dist/server/config.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config/typed-entries.ts","../../src/config/index.ts"],"sourcesContent":["/**\n * Type-Safe Content Entries\n *\n * This module provides type-safe helpers for defining content types and entries\n * in SDK site configurations. When used with `as const`, TypeScript can infer\n * the exact shape of entry data from the content type's field definitions.\n *\n * @example\n * ```typescript\n * import { defineTypedContentType, createEntry, tiptap } from '@riverbankcms/sdk/config';\n *\n * // Define content type with `as const` for type inference\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n *\n * // Create entry with full type safety\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * data: {\n * name: 'John Doe', // TypeScript knows this is string\n * quote: tiptap.paragraph('Great service!'), // TypeScript knows this is TipTapNode\n * },\n * });\n * ```\n */\n\nimport type {\n FieldDefinition,\n TextFieldDefinition,\n RichTextFieldDefinition,\n MediaFieldDefinition,\n BooleanFieldDefinition,\n NumberFieldDefinition,\n DateFieldDefinition,\n TimeFieldDefinition,\n DateTimeFieldDefinition,\n SlugFieldDefinition,\n UrlFieldDefinition,\n LinkFieldDefinition,\n SelectFieldDefinition,\n ReferenceFieldDefinition,\n RepeaterFieldDefinition,\n GroupFieldDefinition,\n ModalFieldDefinition,\n TabGroupFieldDefinition,\n PresetOrCustomFieldDefinition,\n ContentTypeSelectFieldDefinition,\n EntryPickerFieldDefinition,\n TipTapNode,\n Media,\n LinkValue,\n} from '@riverbankcms/blocks';\nimport type { ContentTypeConfig, EntryConfig } from './content-types';\n\n// Re-export value types for convenience\nexport type { TipTapNode, Media, LinkValue } from '@riverbankcms/blocks';\nexport type {\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from '@riverbankcms/blocks';\n\n// =============================================================================\n// Type Infrastructure\n// =============================================================================\n\n/**\n * Infers the data object shape from tabGroup tabs (flattens all tab fields).\n * TabGroup fields flatten all their tab fields into a single data object.\n */\ntype InferDataFromTabs<Tabs extends readonly { fields: readonly FieldDefinition[] }[]> =\n InferDataFromFields<Tabs[number]['fields']>;\n\n// NOTE: Polymorphic repeater type inference would require a helper like this,\n// but TypeScript's mapped types don't distribute correctly over union keys\n// when nested inside conditional types. Left as documentation for future work.\n// type PolymorphicItemData<K, IT> = K extends string\n// ? K extends keyof IT\n// ? IT[K] extends { fields: infer F extends readonly FieldDefinition[] }\n// ? { _type: K } & InferDataFromFields<F>\n// : never\n// : never\n// : never;\n\n/**\n * Maps a field definition to its TypeScript value type.\n * Uses conditional types to infer the correct type based on field.type.\n *\n * Coverage:\n * - Simple primitives: text, boolean, number\n * - Complex types: richText (TipTapNode), media (Media | null), link (LinkValue | null)\n * - Date/time: date, time, datetime (all ISO strings)\n * - String-value: slug, url, reference, presetOrCustom, contentTypeSelect\n * - Select: single (string) vs multiple (string[])\n * - Entry picker: string | null\n * - Nested: group, modal (nested InferDataFromFields)\n * - Repeater: monomorphic (array) and polymorphic (discriminated union array)\n * - TabGroup: flattened fields from all tabs\n */\nexport type FieldValueType<F extends FieldDefinition> =\n // Simple primitives - use specific field types for better inference\n F extends TextFieldDefinition ? string :\n F extends BooleanFieldDefinition ? boolean :\n F extends NumberFieldDefinition ? number :\n // Complex types\n F extends RichTextFieldDefinition ? TipTapNode :\n F extends MediaFieldDefinition ? Media | null :\n F extends LinkFieldDefinition ? LinkValue | null :\n // Date/time types (all stored as ISO strings)\n F extends DateFieldDefinition ? string :\n F extends TimeFieldDefinition ? string :\n F extends DateTimeFieldDefinition ? string :\n // String-value types\n F extends SlugFieldDefinition ? string :\n F extends UrlFieldDefinition ? string :\n F extends ReferenceFieldDefinition ? string :\n F extends PresetOrCustomFieldDefinition ? string :\n F extends ContentTypeSelectFieldDefinition ? string :\n // Select: check multiple flag first (more specific match)\n F extends SelectFieldDefinition & { multiple: true } ? string[] :\n F extends SelectFieldDefinition ? string :\n // Entry picker\n F extends EntryPickerFieldDefinition ? string | null :\n // Nested types (group, modal)\n F extends GroupFieldDefinition & { schema: { fields: infer GF } } ?\n GF extends readonly FieldDefinition[] ? InferDataFromFields<GF> : never :\n F extends ModalFieldDefinition & { schema: { fields: infer MF } } ?\n MF extends readonly FieldDefinition[] ? InferDataFromFields<MF> : never :\n // Repeater types (polymorphic first - more specific, then monomorphic)\n // TODO: Polymorphic repeaters need more complex type distribution.\n // For now, return unknown[] - the runtime data is still correct.\n F extends { type: 'repeater'; polymorphic: true } ? unknown[] :\n F extends RepeaterFieldDefinition & { schema: { fields: infer RF } } ?\n RF extends readonly FieldDefinition[] ? InferDataFromFields<RF>[] : never :\n // TabGroup (flattens all tab fields)\n F extends TabGroupFieldDefinition & { tabs: infer T } ?\n T extends readonly { fields: readonly FieldDefinition[] }[] ?\n InferDataFromTabs<T> : never :\n // Fallback for unknown types\n unknown;\n\n/**\n * Infers the data object shape from an array of field definitions.\n * Required fields are non-optional, optional fields are `| undefined`.\n *\n * @example\n * ```typescript\n * const fields = [\n * { id: 'name', type: 'text', required: true },\n * { id: 'bio', type: 'text', required: false },\n * ] as const;\n *\n * type Data = InferDataFromFields<typeof fields>;\n * // { name: string; bio: string | undefined }\n * ```\n */\nexport type InferDataFromFields<Fields extends readonly FieldDefinition[]> = {\n [F in Fields[number] as F['id']]: F extends { required: true }\n ? FieldValueType<F>\n : FieldValueType<F> | undefined;\n};\n\n// =============================================================================\n// TypedContentType\n// =============================================================================\n\n/**\n * A content type definition with preserved field types for type inference.\n * Extends ContentTypeConfig to ensure all required fields are present.\n * The generic parameters capture the literal types from `as const`.\n */\nexport interface TypedContentType<\n K extends string = string,\n F extends readonly FieldDefinition[] = readonly FieldDefinition[]\n> extends Omit<ContentTypeConfig, 'key' | 'fields'> {\n key: K;\n fields: F;\n}\n\n/**\n * Define a content type with preserved field types for type inference.\n *\n * IMPORTANT: Use `as const` on the config object to enable type inference.\n * Without `as const`, TypeScript widens literal types and inference won't work.\n *\n * @param config - The content type configuration\n * @returns The same config object with preserved types\n *\n * @example\n * ```typescript\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n * ```\n */\nexport function defineTypedContentType<\n K extends string,\n F extends readonly FieldDefinition[]\n>(config: TypedContentType<K, F>): TypedContentType<K, F> {\n return config;\n}\n\n// =============================================================================\n// TypedEntryConfig and createEntry\n// =============================================================================\n\n/**\n * Entry configuration with typed data field.\n * Used internally by createEntry to enforce type safety.\n */\nexport interface TypedEntryConfig<Data extends Record<string, unknown>> {\n /** Unique identifier for this entry. Required for SDK sync. */\n identifier: string;\n /** Title for the entry */\n title?: string;\n /** Slug for routable entries */\n slug?: string;\n /** Status: 'draft' or 'published' */\n status?: 'draft' | 'published';\n /** Summary/description */\n summary?: string;\n /** SEO meta title */\n metaTitle?: string;\n /** SEO meta description */\n metaDescription?: string;\n /** Entry data matching the content type's field definitions */\n data: Data;\n}\n\n/**\n * Create a type-safe content entry for a typed content type.\n *\n * The data field is validated against the content type's field definitions.\n * TypeScript will error if:\n * - A required field is missing\n * - A field name is misspelled\n * - A field value has the wrong type\n * - An extra field is provided (with strict mode)\n *\n * @param contentType - The typed content type definition\n * @param entry - The entry configuration with typed data\n * @returns EntryConfig compatible with SDK content configuration\n *\n * @example\n * ```typescript\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * title: 'John Doe',\n * status: 'published',\n * data: {\n * name: 'John Doe',\n * quote: tiptap.paragraph('Great service!'),\n * },\n * });\n * ```\n */\nexport function createEntry<\n K extends string,\n F extends readonly FieldDefinition[]\n>(\n contentType: TypedContentType<K, F>,\n entry: TypedEntryConfig<InferDataFromFields<F>>\n): EntryConfig {\n return {\n ...entry,\n contentType: contentType.key,\n };\n}\n\n// =============================================================================\n// TipTap Helpers\n// =============================================================================\n\n/**\n * Helpers for creating TipTap document structures.\n *\n * Use these helpers when populating richText fields to avoid manually\n * constructing the TipTap JSON structure.\n *\n * @example\n * ```typescript\n * // Simple paragraph\n * const body = tiptap.paragraph('Hello, world!');\n *\n * // Empty document\n * const emptyDoc = tiptap.empty();\n *\n * // Complex document\n * const doc = tiptap.doc([\n * tiptap.heading(1, 'Welcome'),\n * { type: 'paragraph', content: [{ type: 'text', text: 'Introduction...' }] },\n * ]);\n * ```\n */\nexport const tiptap = {\n /**\n * Create an empty TipTap document.\n *\n * @returns An empty TipTap document node\n */\n empty(): TipTapNode {\n return { type: 'doc', content: [] };\n },\n\n /**\n * Create a TipTap document with a single paragraph.\n *\n * @param text - The paragraph text content\n * @returns A TipTap document with one paragraph\n */\n paragraph(text: string): TipTapNode {\n return {\n type: 'doc',\n content: [\n {\n type: 'paragraph',\n content: text ? [{ type: 'text', text }] : [],\n },\n ],\n };\n },\n\n /**\n * Create a TipTap document with custom content nodes.\n *\n * @param content - Array of TipTap nodes to include in the document\n * @returns A TipTap document wrapping the content\n */\n doc(content: TipTapNode[]): TipTapNode {\n return { type: 'doc', content };\n },\n\n /**\n * Create a heading node.\n *\n * Note: This returns a heading node, not a document. Use with tiptap.doc()\n * to create a complete document.\n *\n * @param level - Heading level (1-6)\n * @param text - Heading text content\n * @returns A TipTap heading node\n */\n heading(level: 1 | 2 | 3 | 4 | 5 | 6, text: string): TipTapNode {\n return {\n type: 'heading',\n attrs: { level },\n content: [{ type: 'text', text }],\n };\n },\n};\n","/**\n * SDK Site Configuration\n *\n * Types and utilities for defining site-level configuration\n * that SDK sites expose to the dashboard.\n */\n\nimport type { RiverbankSiteConfig, ContentConfig } from './types';\n\n// Types\nexport type {\n RiverbankSiteConfig,\n SiteStyleConfig,\n SectionBackground,\n SectionOptionsConfig,\n ContainerOptionsConfig,\n SectionSpacing,\n ContainerMaxWidth,\n ContainerAlignment,\n SdkThemeConfig,\n SdkThemePalette,\n SdkCustomBlock,\n FieldSelectOption,\n BlockFieldConfig,\n BlockFieldOptionsMap,\n BlockFieldExtension,\n BlockFieldExtensionsMap,\n FieldDefinition,\n // Content scaffolding types\n ContentConfig,\n ContentTypeConfig,\n PageConfig,\n EntryConfig,\n BlockConfig,\n NavigationMenuConfig,\n NavigationItemConfig,\n NavigationLinkType,\n SiteSettingsConfig,\n} from './types';\n\n// Validation schemas\nexport {\n riverbankSiteConfigSchema,\n siteStyleConfigSchema,\n sectionBackgroundSchema,\n sectionSpacingSchema,\n containerMaxWidthSchema,\n containerAlignmentSchema,\n sectionOptionsSchema,\n containerOptionsSchema,\n sdkThemeConfigSchema,\n sdkThemePaletteSchema,\n sdkCustomBlockSchema,\n fieldSelectOptionSchema,\n blockFieldConfigSchema,\n blockFieldOptionsSchema,\n blockFieldExtensionSchema,\n blockFieldExtensionsSchema,\n // Content scaffolding schemas\n contentConfigSchema,\n} from './validation';\n\n// Content validation schemas for more granular use\nexport {\n contentTypeConfigSchema,\n pageConfigSchema,\n entryConfigSchema,\n navigationMenuConfigSchema,\n navigationItemConfigSchema,\n siteSettingsConfigSchema,\n blockConfigSchema,\n} from './content-validation';\n\nexport type {\n ValidatedRiverbankSiteConfig,\n ValidatedSdkCustomBlock,\n ContentConfigInput,\n ContentConfigOutput,\n} from './validation';\n\n// Block kind types (single source of truth from @riverbankcms/blocks)\nexport {\n SYSTEM_BLOCK_KINDS,\n type SystemBlockKind,\n type CustomBlockKind,\n type BlockKind,\n} from '../types';\n\n// Type-safe content entry helpers\nexport {\n defineTypedContentType,\n createEntry,\n tiptap,\n type TypedContentType,\n type TypedEntryConfig,\n type InferDataFromFields,\n type FieldValueType,\n} from './typed-entries';\n\n// Re-export value types for convenience when building entry data\nexport type {\n TipTapNode,\n Media,\n LinkValue,\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from './typed-entries';\n\n/**\n * Helper function to define a Builder site configuration with type checking.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@riverbankcms/sdk/config';\n *\n * export default defineConfig({\n * siteId: '123e4567-e89b-12d3-a456-426614174000',\n * theme: {\n * palette: {\n * primary: '#6d28d9',\n * },\n * },\n * styles: {\n * sectionBackgrounds: [\n * { id: 'primary', label: 'Purple', token: 'primary' },\n * ],\n * },\n * });\n * ```\n */\nexport function defineConfig(config: RiverbankSiteConfig): RiverbankSiteConfig {\n return config;\n}\n\n/**\n * Helper function to define content scaffolding configuration with type checking.\n *\n * This can be used to define content configuration in a separate file,\n * which is then imported into riverbank.config.ts.\n *\n * @example\n * ```typescript\n * // content.config.ts\n * import { defineContentConfig } from '@riverbankcms/sdk/config';\n *\n * export const contentConfig = defineContentConfig({\n * contentTypes: [\n * {\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'quote', type: 'richText', label: 'Quote', required: true },\n * ],\n * },\n * ],\n * pages: [\n * { identifier: 'home', title: 'Home', path: '/' },\n * ],\n * });\n *\n * // riverbank.config.ts\n * import { defineConfig } from '@riverbankcms/sdk/config';\n * import { contentConfig } from './content.config';\n *\n * export default defineConfig({\n * siteId: '...',\n * content: contentConfig,\n * });\n * ```\n */\nexport function defineContentConfig(config: ContentConfig): ContentConfig {\n return config;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgNO,SAAS,uBAGd,QAAwD;AACxD,SAAO;AACT;AAwDO,SAAS,YAId,aACA,OACa;AACb,SAAO;AAAA,IACL,GAAG;AAAA,IACH,aAAa,YAAY;AAAA,EAC3B;AACF;AA2BO,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpB,QAAoB;AAClB,WAAO,EAAE,MAAM,OAAO,SAAS,CAAC,EAAE;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,MAA0B;AAClC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,SAAmC;AACrC,WAAO,EAAE,MAAM,OAAO,QAAQ;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAQ,OAA8B,MAA0B;AAC9D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,MAAM;AAAA,MACf,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,IAClC;AAAA,EACF;AACF;;;ACvOO,SAAS,aAAa,QAAkD;AAC7E,SAAO;AACT;AAuCO,SAAS,oBAAoB,QAAsC;AACxE,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/config/typed-entries.ts","../../src/config/index.ts"],"sourcesContent":["/**\n * Type-Safe Content Entries\n *\n * This module provides type-safe helpers for defining content types and entries\n * in SDK site configurations. When used with `as const`, TypeScript can infer\n * the exact shape of entry data from the content type's field definitions.\n *\n * @example\n * ```typescript\n * import { defineTypedContentType, createEntry, tiptap } from '@riverbankcms/sdk/config';\n *\n * // Define content type with `as const` for type inference\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n *\n * // Create entry with full type safety\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * data: {\n * name: 'John Doe', // TypeScript knows this is string\n * quote: tiptap.paragraph('Great service!'), // TypeScript knows this is TipTapNode\n * },\n * });\n * ```\n */\n\nimport type {\n FieldDefinition,\n TextFieldDefinition,\n RichTextFieldDefinition,\n MediaFieldDefinition,\n BooleanFieldDefinition,\n NumberFieldDefinition,\n DateFieldDefinition,\n TimeFieldDefinition,\n DateTimeFieldDefinition,\n SlugFieldDefinition,\n UrlFieldDefinition,\n LinkFieldDefinition,\n SelectFieldDefinition,\n ReferenceFieldDefinition,\n RepeaterFieldDefinition,\n GroupFieldDefinition,\n ModalFieldDefinition,\n TabGroupFieldDefinition,\n PresetOrCustomFieldDefinition,\n ContentTypeSelectFieldDefinition,\n EntryPickerFieldDefinition,\n TipTapNode,\n Media,\n LinkValue,\n} from '@riverbankcms/blocks';\nimport type { ContentTypeConfig, EntryConfig } from './content-types';\n\n// Re-export value types for convenience\nexport type { TipTapNode, Media, LinkValue } from '@riverbankcms/blocks';\nexport type {\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from '@riverbankcms/blocks';\n\n// =============================================================================\n// Type Infrastructure\n// =============================================================================\n\n/**\n * Infers the data object shape from tabGroup tabs (flattens all tab fields).\n * TabGroup fields flatten all their tab fields into a single data object.\n */\ntype InferDataFromTabs<Tabs extends readonly { fields: readonly FieldDefinition[] }[]> =\n InferDataFromFields<Tabs[number]['fields']>;\n\n// NOTE: Polymorphic repeater type inference would require a helper like this,\n// but TypeScript's mapped types don't distribute correctly over union keys\n// when nested inside conditional types. Left as documentation for future work.\n// type PolymorphicItemData<K, IT> = K extends string\n// ? K extends keyof IT\n// ? IT[K] extends { fields: infer F extends readonly FieldDefinition[] }\n// ? { _type: K } & InferDataFromFields<F>\n// : never\n// : never\n// : never;\n\n/**\n * Maps a field definition to its TypeScript value type.\n * Uses conditional types to infer the correct type based on field.type.\n *\n * Coverage:\n * - Simple primitives: text, boolean, number\n * - Complex types: richText (TipTapNode), media (Media | null), link (LinkValue | null)\n * - Date/time: date, time, datetime (all ISO strings)\n * - String-value: slug, url, reference, presetOrCustom, contentTypeSelect\n * - Select: single (string) vs multiple (string[])\n * - Entry picker: string | null\n * - Nested: group, modal (nested InferDataFromFields)\n * - Repeater: monomorphic (array) and polymorphic (discriminated union array)\n * - TabGroup: flattened fields from all tabs\n */\nexport type FieldValueType<F extends FieldDefinition> =\n // Simple primitives - use specific field types for better inference\n F extends TextFieldDefinition ? string :\n F extends BooleanFieldDefinition ? boolean :\n F extends NumberFieldDefinition ? number :\n // Complex types\n F extends RichTextFieldDefinition ? TipTapNode :\n F extends MediaFieldDefinition ? Media | null :\n F extends LinkFieldDefinition ? LinkValue | null :\n // Date/time types (all stored as ISO strings)\n F extends DateFieldDefinition ? string :\n F extends TimeFieldDefinition ? string :\n F extends DateTimeFieldDefinition ? string :\n // String-value types\n F extends SlugFieldDefinition ? string :\n F extends UrlFieldDefinition ? string :\n F extends ReferenceFieldDefinition ? string :\n F extends PresetOrCustomFieldDefinition ? string :\n F extends ContentTypeSelectFieldDefinition ? string :\n // Select: check multiple flag first (more specific match)\n F extends SelectFieldDefinition & { multiple: true } ? string[] :\n F extends SelectFieldDefinition ? string :\n // Entry picker\n F extends EntryPickerFieldDefinition ? string | null :\n // Nested types (group, modal)\n F extends GroupFieldDefinition & { schema: { fields: infer GF } } ?\n GF extends readonly FieldDefinition[] ? InferDataFromFields<GF> : never :\n F extends ModalFieldDefinition & { schema: { fields: infer MF } } ?\n MF extends readonly FieldDefinition[] ? InferDataFromFields<MF> : never :\n // Repeater types (polymorphic first - more specific, then monomorphic)\n // TODO: Polymorphic repeaters need more complex type distribution.\n // For now, return unknown[] - the runtime data is still correct.\n F extends { type: 'repeater'; polymorphic: true } ? unknown[] :\n F extends RepeaterFieldDefinition & { schema: { fields: infer RF } } ?\n RF extends readonly FieldDefinition[] ? InferDataFromFields<RF>[] : never :\n // TabGroup (flattens all tab fields)\n F extends TabGroupFieldDefinition & { tabs: infer T } ?\n T extends readonly { fields: readonly FieldDefinition[] }[] ?\n InferDataFromTabs<T> : never :\n // Fallback for unknown types\n unknown;\n\n/**\n * Infers the data object shape from an array of field definitions.\n * Required fields are non-optional, optional fields are `| undefined`.\n *\n * @example\n * ```typescript\n * const fields = [\n * { id: 'name', type: 'text', required: true },\n * { id: 'bio', type: 'text', required: false },\n * ] as const;\n *\n * type Data = InferDataFromFields<typeof fields>;\n * // { name: string; bio: string | undefined }\n * ```\n */\nexport type InferDataFromFields<Fields extends readonly FieldDefinition[]> = {\n [F in Fields[number] as F['id']]: F extends { required: true }\n ? FieldValueType<F>\n : FieldValueType<F> | undefined;\n};\n\n// =============================================================================\n// TypedContentType\n// =============================================================================\n\n/**\n * A content type definition with preserved field types for type inference.\n * Extends ContentTypeConfig to ensure all required fields are present.\n * The generic parameters capture the literal types from `as const`.\n */\nexport interface TypedContentType<\n K extends string = string,\n F extends readonly FieldDefinition[] = readonly FieldDefinition[]\n> extends Omit<ContentTypeConfig, 'key' | 'fields'> {\n key: K;\n fields: F;\n}\n\n/**\n * Define a content type with preserved field types for type inference.\n *\n * IMPORTANT: Use `as const` on the config object to enable type inference.\n * Without `as const`, TypeScript widens literal types and inference won't work.\n *\n * @param config - The content type configuration\n * @returns The same config object with preserved types\n *\n * @example\n * ```typescript\n * export const testimonialType = defineTypedContentType({\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'name', type: 'text', label: 'Name', required: true, multiline: false },\n * { id: 'quote', type: 'richText', label: 'Quote', required: true, format: 'html' },\n * ],\n * } as const);\n * ```\n */\nexport function defineTypedContentType<\n K extends string,\n F extends readonly FieldDefinition[]\n>(config: TypedContentType<K, F>): TypedContentType<K, F> {\n return config;\n}\n\n// =============================================================================\n// TypedEntryConfig and createEntry\n// =============================================================================\n\n/**\n * Entry configuration with typed data field.\n * Used internally by createEntry to enforce type safety.\n */\nexport interface TypedEntryConfig<Data extends Record<string, unknown>> {\n /** Unique identifier for this entry. Required for SDK sync. */\n identifier: string;\n /** Title for the entry */\n title?: string;\n /** Slug for routable entries */\n slug?: string;\n /** Status: 'draft' or 'published' */\n status?: 'draft' | 'published';\n /** Summary/description */\n summary?: string;\n /** SEO meta title */\n metaTitle?: string;\n /** SEO meta description */\n metaDescription?: string;\n /** Entry data matching the content type's field definitions */\n data: Data;\n}\n\n/**\n * Create a type-safe content entry for a typed content type.\n *\n * The data field is validated against the content type's field definitions.\n * TypeScript will error if:\n * - A required field is missing\n * - A field name is misspelled\n * - A field value has the wrong type\n * - An extra field is provided (with strict mode)\n *\n * @param contentType - The typed content type definition\n * @param entry - The entry configuration with typed data\n * @returns EntryConfig compatible with SDK content configuration\n *\n * @example\n * ```typescript\n * const entry = createEntry(testimonialType, {\n * identifier: 'testimonial-1',\n * title: 'John Doe',\n * status: 'published',\n * data: {\n * name: 'John Doe',\n * quote: tiptap.paragraph('Great service!'),\n * },\n * });\n * ```\n */\nexport function createEntry<\n K extends string,\n F extends readonly FieldDefinition[]\n>(\n contentType: TypedContentType<K, F>,\n entry: TypedEntryConfig<InferDataFromFields<F>>\n): EntryConfig {\n return {\n ...entry,\n contentType: contentType.key,\n };\n}\n\n// =============================================================================\n// TipTap Helpers\n// =============================================================================\n\n/**\n * Helpers for creating TipTap document structures.\n *\n * Use these helpers when populating richText fields to avoid manually\n * constructing the TipTap JSON structure.\n *\n * @example\n * ```typescript\n * // Simple paragraph\n * const body = tiptap.paragraph('Hello, world!');\n *\n * // Empty document\n * const emptyDoc = tiptap.empty();\n *\n * // Complex document\n * const doc = tiptap.doc([\n * tiptap.heading(1, 'Welcome'),\n * { type: 'paragraph', content: [{ type: 'text', text: 'Introduction...' }] },\n * ]);\n * ```\n */\nexport const tiptap = {\n /**\n * Create an empty TipTap document.\n *\n * @returns An empty TipTap document node\n */\n empty(): TipTapNode {\n return { type: 'doc', content: [] };\n },\n\n /**\n * Create a TipTap document with a single paragraph.\n *\n * @param text - The paragraph text content\n * @returns A TipTap document with one paragraph\n */\n paragraph(text: string): TipTapNode {\n return {\n type: 'doc',\n content: [\n {\n type: 'paragraph',\n content: text ? [{ type: 'text', text }] : [],\n },\n ],\n };\n },\n\n /**\n * Create a TipTap document with custom content nodes.\n *\n * @param content - Array of TipTap nodes to include in the document\n * @returns A TipTap document wrapping the content\n */\n doc(content: TipTapNode[]): TipTapNode {\n return { type: 'doc', content };\n },\n\n /**\n * Create a heading node.\n *\n * Note: This returns a heading node, not a document. Use with tiptap.doc()\n * to create a complete document.\n *\n * @param level - Heading level (1-6)\n * @param text - Heading text content\n * @returns A TipTap heading node\n */\n heading(level: 1 | 2 | 3 | 4 | 5 | 6, text: string): TipTapNode {\n return {\n type: 'heading',\n attrs: { level },\n content: [{ type: 'text', text }],\n };\n },\n};\n","/**\n * SDK Site Configuration\n *\n * Types and utilities for defining site-level configuration\n * that SDK sites expose to the dashboard.\n */\n\nimport type { RiverbankSiteConfig, ContentConfig } from './types';\n\n// Types\nexport type {\n RiverbankSiteConfig,\n SiteStyleConfig,\n SectionBackground,\n SectionOptionsConfig,\n ContainerOptionsConfig,\n SectionSpacing,\n ContainerMaxWidth,\n ContainerAlignment,\n SdkThemeConfig,\n SdkThemePalette,\n SdkCustomBlock,\n FieldSelectOption,\n BlockFieldConfig,\n BlockFieldOptionsMap,\n BlockFieldExtension,\n BlockFieldExtensionsMap,\n FieldDefinition,\n // Content scaffolding types\n ContentConfig,\n ContentTypeConfig,\n PageConfig,\n EntryConfig,\n BlockConfig,\n NavigationMenuConfig,\n NavigationItemConfig,\n NavigationLinkType,\n SiteSettingsConfig,\n} from './types';\n\n// Validation schemas\nexport {\n riverbankSiteConfigSchema,\n siteStyleConfigSchema,\n sectionBackgroundSchema,\n sectionSpacingSchema,\n containerMaxWidthSchema,\n containerAlignmentSchema,\n sectionOptionsSchema,\n containerOptionsSchema,\n sdkThemeConfigSchema,\n sdkThemePaletteSchema,\n sdkCustomBlockSchema,\n fieldSelectOptionSchema,\n blockFieldConfigSchema,\n blockFieldOptionsSchema,\n blockFieldExtensionSchema,\n blockFieldExtensionsSchema,\n // Content scaffolding schemas\n contentConfigSchema,\n} from './validation';\n\n// Content validation schemas for more granular use\nexport {\n contentTypeConfigSchema,\n pageConfigSchema,\n entryConfigSchema,\n navigationMenuConfigSchema,\n navigationItemConfigSchema,\n siteSettingsConfigSchema,\n blockConfigSchema,\n} from './content-validation';\n\nexport type {\n ValidatedRiverbankSiteConfig,\n ValidatedSdkCustomBlock,\n ContentConfigInput,\n ContentConfigOutput,\n} from './validation';\n\n// Block kind types (single source of truth from @riverbankcms/blocks)\nexport {\n SYSTEM_BLOCK_KINDS,\n type SystemBlockKind,\n type CustomBlockKind,\n type BlockKind,\n} from '../types';\n\n// Type-safe content entry helpers\nexport {\n defineTypedContentType,\n createEntry,\n tiptap,\n type TypedContentType,\n type TypedEntryConfig,\n type InferDataFromFields,\n type FieldValueType,\n} from './typed-entries';\n\n// Re-export value types for convenience when building entry data\nexport type {\n TipTapNode,\n Media,\n LinkValue,\n InternalLinkValue,\n ExternalLinkValue,\n CustomLinkValue,\n} from './typed-entries';\n\n/**\n * Helper function to define a Builder site configuration with type checking.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@riverbankcms/sdk/config';\n *\n * export default defineConfig({\n * siteId: '123e4567-e89b-12d3-a456-426614174000',\n * theme: {\n * palette: {\n * primary: '#6d28d9',\n * },\n * },\n * styles: {\n * sectionBackgrounds: [\n * { id: 'primary', label: 'Purple', token: 'primary' },\n * ],\n * },\n * });\n * ```\n */\nexport function defineConfig(config: RiverbankSiteConfig): RiverbankSiteConfig {\n return config;\n}\n\n/**\n * Helper function to define content scaffolding configuration with type checking.\n *\n * This can be used to define content configuration in a separate file,\n * which is then imported into riverbank.config.ts.\n *\n * @example\n * ```typescript\n * // content.config.ts\n * import { defineContentConfig } from '@riverbankcms/sdk/config';\n *\n * export const contentConfig = defineContentConfig({\n * contentTypes: [\n * {\n * key: 'testimonial',\n * name: 'Testimonial',\n * hasPages: false,\n * fields: [\n * { id: 'quote', type: 'richText', label: 'Quote', required: true },\n * ],\n * },\n * ],\n * pages: [\n * { identifier: 'home', title: 'Home', path: '/' },\n * ],\n * });\n *\n * // riverbank.config.ts\n * import { defineConfig } from '@riverbankcms/sdk/config';\n * import { contentConfig } from './content.config';\n *\n * export default defineConfig({\n * siteId: '...',\n * content: contentConfig,\n * });\n * ```\n */\nexport function defineContentConfig(config: ContentConfig): ContentConfig {\n return config;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgNO,SAAS,uBAGd,QAAwD;AACxD,SAAO;AACT;AAwDO,SAAS,YAId,aACA,OACa;AACb,SAAO;AAAA,IACL,GAAG;AAAA,IACH,aAAa,YAAY;AAAA,EAC3B;AACF;AA2BO,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpB,QAAoB;AAClB,WAAO,EAAE,MAAM,OAAO,SAAS,CAAC,EAAE;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,MAA0B;AAClC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,IAAI,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,SAAmC;AACrC,WAAO,EAAE,MAAM,OAAO,QAAQ;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAQ,OAA8B,MAA0B;AAC9D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,MAAM;AAAA,MACf,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,IAClC;AAAA,EACF;AACF;;;ACvOO,SAAS,aAAa,QAAkD;AAC7E,SAAO;AACT;AAuCO,SAAS,oBAAoB,QAAsC;AACxE,SAAO;AACT;","names":[]}
|
package/dist/server/data.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { P as PageOutline, S as SdkCustomBlock } from './schema-Z6-afHJG.mjs';
|
|
2
2
|
import { P as PrefetchContext, R as ResolvedBlockData, D as DataLoaderOverrides } from './types-CbagRQ_7.mjs';
|
|
3
3
|
export { B as BlockLoaderMap, a as DataLoaderContext, b as DataLoaderFn } from './types-CbagRQ_7.mjs';
|
|
4
|
-
import { R as RiverbankClient } from './types-
|
|
4
|
+
import { R as RiverbankClient } from './types-C-LShyIg.mjs';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './blockKinds-B6MWzNWp.mjs';
|
|
7
|
-
import './types-
|
|
7
|
+
import './types-BSV6Vc-P.mjs';
|
|
8
8
|
import '@riverbankcms/ai';
|
|
9
9
|
import './link-DjxLyC82.mjs';
|
|
10
10
|
import '@riverbankcms/media-storage-supabase';
|
package/dist/server/data.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { P as PageOutline, S as SdkCustomBlock } from './schema-Z6-afHJG.js';
|
|
2
2
|
import { P as PrefetchContext, R as ResolvedBlockData, D as DataLoaderOverrides } from './types-DuQCNVV0.js';
|
|
3
3
|
export { B as BlockLoaderMap, a as DataLoaderContext, b as DataLoaderFn } from './types-DuQCNVV0.js';
|
|
4
|
-
import { R as RiverbankClient } from './types-
|
|
4
|
+
import { R as RiverbankClient } from './types-BRQyLrQU.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import './blockKinds-B6MWzNWp.js';
|
|
7
|
-
import './types-
|
|
7
|
+
import './types-Dt98DeYa.js';
|
|
8
8
|
import '@riverbankcms/ai';
|
|
9
9
|
import './link-DjxLyC82.js';
|
|
10
10
|
import '@riverbankcms/media-storage-supabase';
|
package/dist/server/data.js
CHANGED
package/dist/server/data.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/data.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACF,qRAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/data.js"}
|
|
1
|
+
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/data.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACF,qRAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/data.js"}
|
package/dist/server/data.mjs
CHANGED
package/dist/server/env.d.mts
CHANGED
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Environment detection utilities for SDK
|
|
3
3
|
*
|
|
4
|
-
* Provides helpers for detecting preview mode and
|
|
4
|
+
* Provides helpers for detecting preview mode and auto-selecting the correct API key.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { getRiverbankEnv } from '@riverbankcms/sdk/env';
|
|
9
|
+
* import { createRiverbankClient } from '@riverbankcms/sdk';
|
|
10
|
+
*
|
|
11
|
+
* const env = getRiverbankEnv();
|
|
12
|
+
* const client = createRiverbankClient({
|
|
13
|
+
* apiKey: env.apiKey,
|
|
14
|
+
* baseUrl: env.baseUrl,
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Environment target: 'local' for development, 'remote' for production
|
|
20
|
+
*/
|
|
21
|
+
type RiverbankEnvTarget = 'local' | 'remote';
|
|
22
|
+
/**
|
|
23
|
+
* Runtime environment configuration
|
|
5
24
|
*/
|
|
25
|
+
interface RiverbankEnvConfig {
|
|
26
|
+
/** The detected environment target */
|
|
27
|
+
target: RiverbankEnvTarget;
|
|
28
|
+
/** Whether preview mode is enabled */
|
|
29
|
+
previewMode: boolean;
|
|
30
|
+
/** Site ID */
|
|
31
|
+
siteId: string;
|
|
32
|
+
/** Dashboard/API base URL */
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
/** The auto-selected API key (preview or content key based on mode) */
|
|
35
|
+
apiKey: string;
|
|
36
|
+
/** The type of key being used */
|
|
37
|
+
keyType: 'preview' | 'content';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Error thrown when required environment variables are missing
|
|
41
|
+
*/
|
|
42
|
+
declare class RiverbankEnvError extends Error {
|
|
43
|
+
readonly missingVars: string[];
|
|
44
|
+
constructor(message: string, missingVars: string[]);
|
|
45
|
+
}
|
|
6
46
|
/**
|
|
7
47
|
* Detects if the current environment is in preview mode.
|
|
8
48
|
*
|
|
9
49
|
* Precedence:
|
|
10
|
-
* 1.
|
|
11
|
-
* 2.
|
|
12
|
-
* 3.
|
|
50
|
+
* 1. RIVERBANK_PREVIEW_MODE env var (explicit override) - 'true' or 'false'
|
|
51
|
+
* 2. RIVERBANK_PREVIEW env var (legacy) - 'true' or 'false'
|
|
52
|
+
* 3. VERCEL_ENV === 'preview' (Vercel preview deployments)
|
|
53
|
+
* 4. Default: false (production behavior)
|
|
13
54
|
*
|
|
14
55
|
* In preview mode:
|
|
15
56
|
* - Draft content is visible
|
|
@@ -19,5 +60,50 @@
|
|
|
19
60
|
* @returns true if in preview mode, false otherwise
|
|
20
61
|
*/
|
|
21
62
|
declare function isPreviewMode(): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Get the current environment target.
|
|
65
|
+
*
|
|
66
|
+
* This is a convenience function for checking `RIVERBANK_ENV`.
|
|
67
|
+
*
|
|
68
|
+
* @returns 'local' or 'remote'
|
|
69
|
+
*/
|
|
70
|
+
declare function getRiverbankTarget(): RiverbankEnvTarget;
|
|
71
|
+
/**
|
|
72
|
+
* Get runtime environment configuration with automatic API key selection.
|
|
73
|
+
*
|
|
74
|
+
* This helper reads environment variables and automatically selects the correct
|
|
75
|
+
* API key based on the current environment and preview mode:
|
|
76
|
+
*
|
|
77
|
+
* - When `RIVERBANK_PREVIEW_MODE=true`: Uses preview API key (bld_preview_sk_...)
|
|
78
|
+
* - When `RIVERBANK_PREVIEW_MODE=false` (default): Uses content API key (bld_live_sk_...)
|
|
79
|
+
*
|
|
80
|
+
* Environment variable patterns:
|
|
81
|
+
* - `RIVERBANK_ENV`: 'local' (default) or 'remote'
|
|
82
|
+
* - `RIVERBANK_PREVIEW_MODE`: 'true' or 'false' (default)
|
|
83
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_SITE_ID`: Site ID
|
|
84
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_DASHBOARD_URL`: Dashboard URL
|
|
85
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_API_KEY`: Content/live API key
|
|
86
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_PREVIEW_API_KEY`: Preview API key
|
|
87
|
+
*
|
|
88
|
+
* @returns Environment configuration with auto-selected API key
|
|
89
|
+
* @throws {RiverbankEnvError} If required environment variables are missing
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* // lib/builder-client.ts
|
|
94
|
+
* import { getRiverbankEnv } from '@riverbankcms/sdk/env';
|
|
95
|
+
* import { createRiverbankClient } from '@riverbankcms/sdk';
|
|
96
|
+
*
|
|
97
|
+
* const env = getRiverbankEnv();
|
|
98
|
+
*
|
|
99
|
+
* export const client = createRiverbankClient({
|
|
100
|
+
* apiKey: env.apiKey,
|
|
101
|
+
* baseUrl: env.baseUrl,
|
|
102
|
+
* });
|
|
103
|
+
*
|
|
104
|
+
* export const siteId = env.siteId;
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function getRiverbankEnv(): RiverbankEnvConfig;
|
|
22
108
|
|
|
23
|
-
export { isPreviewMode };
|
|
109
|
+
export { type RiverbankEnvConfig, RiverbankEnvError, type RiverbankEnvTarget, getRiverbankEnv, getRiverbankTarget, isPreviewMode };
|
package/dist/server/env.d.ts
CHANGED
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Environment detection utilities for SDK
|
|
3
3
|
*
|
|
4
|
-
* Provides helpers for detecting preview mode and
|
|
4
|
+
* Provides helpers for detecting preview mode and auto-selecting the correct API key.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { getRiverbankEnv } from '@riverbankcms/sdk/env';
|
|
9
|
+
* import { createRiverbankClient } from '@riverbankcms/sdk';
|
|
10
|
+
*
|
|
11
|
+
* const env = getRiverbankEnv();
|
|
12
|
+
* const client = createRiverbankClient({
|
|
13
|
+
* apiKey: env.apiKey,
|
|
14
|
+
* baseUrl: env.baseUrl,
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Environment target: 'local' for development, 'remote' for production
|
|
20
|
+
*/
|
|
21
|
+
type RiverbankEnvTarget = 'local' | 'remote';
|
|
22
|
+
/**
|
|
23
|
+
* Runtime environment configuration
|
|
5
24
|
*/
|
|
25
|
+
interface RiverbankEnvConfig {
|
|
26
|
+
/** The detected environment target */
|
|
27
|
+
target: RiverbankEnvTarget;
|
|
28
|
+
/** Whether preview mode is enabled */
|
|
29
|
+
previewMode: boolean;
|
|
30
|
+
/** Site ID */
|
|
31
|
+
siteId: string;
|
|
32
|
+
/** Dashboard/API base URL */
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
/** The auto-selected API key (preview or content key based on mode) */
|
|
35
|
+
apiKey: string;
|
|
36
|
+
/** The type of key being used */
|
|
37
|
+
keyType: 'preview' | 'content';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Error thrown when required environment variables are missing
|
|
41
|
+
*/
|
|
42
|
+
declare class RiverbankEnvError extends Error {
|
|
43
|
+
readonly missingVars: string[];
|
|
44
|
+
constructor(message: string, missingVars: string[]);
|
|
45
|
+
}
|
|
6
46
|
/**
|
|
7
47
|
* Detects if the current environment is in preview mode.
|
|
8
48
|
*
|
|
9
49
|
* Precedence:
|
|
10
|
-
* 1.
|
|
11
|
-
* 2.
|
|
12
|
-
* 3.
|
|
50
|
+
* 1. RIVERBANK_PREVIEW_MODE env var (explicit override) - 'true' or 'false'
|
|
51
|
+
* 2. RIVERBANK_PREVIEW env var (legacy) - 'true' or 'false'
|
|
52
|
+
* 3. VERCEL_ENV === 'preview' (Vercel preview deployments)
|
|
53
|
+
* 4. Default: false (production behavior)
|
|
13
54
|
*
|
|
14
55
|
* In preview mode:
|
|
15
56
|
* - Draft content is visible
|
|
@@ -19,5 +60,50 @@
|
|
|
19
60
|
* @returns true if in preview mode, false otherwise
|
|
20
61
|
*/
|
|
21
62
|
declare function isPreviewMode(): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Get the current environment target.
|
|
65
|
+
*
|
|
66
|
+
* This is a convenience function for checking `RIVERBANK_ENV`.
|
|
67
|
+
*
|
|
68
|
+
* @returns 'local' or 'remote'
|
|
69
|
+
*/
|
|
70
|
+
declare function getRiverbankTarget(): RiverbankEnvTarget;
|
|
71
|
+
/**
|
|
72
|
+
* Get runtime environment configuration with automatic API key selection.
|
|
73
|
+
*
|
|
74
|
+
* This helper reads environment variables and automatically selects the correct
|
|
75
|
+
* API key based on the current environment and preview mode:
|
|
76
|
+
*
|
|
77
|
+
* - When `RIVERBANK_PREVIEW_MODE=true`: Uses preview API key (bld_preview_sk_...)
|
|
78
|
+
* - When `RIVERBANK_PREVIEW_MODE=false` (default): Uses content API key (bld_live_sk_...)
|
|
79
|
+
*
|
|
80
|
+
* Environment variable patterns:
|
|
81
|
+
* - `RIVERBANK_ENV`: 'local' (default) or 'remote'
|
|
82
|
+
* - `RIVERBANK_PREVIEW_MODE`: 'true' or 'false' (default)
|
|
83
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_SITE_ID`: Site ID
|
|
84
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_DASHBOARD_URL`: Dashboard URL
|
|
85
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_API_KEY`: Content/live API key
|
|
86
|
+
* - `RIVERBANK_{LOCAL|REMOTE}_PREVIEW_API_KEY`: Preview API key
|
|
87
|
+
*
|
|
88
|
+
* @returns Environment configuration with auto-selected API key
|
|
89
|
+
* @throws {RiverbankEnvError} If required environment variables are missing
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* // lib/builder-client.ts
|
|
94
|
+
* import { getRiverbankEnv } from '@riverbankcms/sdk/env';
|
|
95
|
+
* import { createRiverbankClient } from '@riverbankcms/sdk';
|
|
96
|
+
*
|
|
97
|
+
* const env = getRiverbankEnv();
|
|
98
|
+
*
|
|
99
|
+
* export const client = createRiverbankClient({
|
|
100
|
+
* apiKey: env.apiKey,
|
|
101
|
+
* baseUrl: env.baseUrl,
|
|
102
|
+
* });
|
|
103
|
+
*
|
|
104
|
+
* export const siteId = env.siteId;
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function getRiverbankEnv(): RiverbankEnvConfig;
|
|
22
108
|
|
|
23
|
-
export { isPreviewMode };
|
|
109
|
+
export { type RiverbankEnvConfig, RiverbankEnvError, type RiverbankEnvTarget, getRiverbankEnv, getRiverbankTarget, isPreviewMode };
|
package/dist/server/env.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var _chunkWYNEYDXOjs = require('./chunk-WYNEYDXO.js');
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
|
|
6
|
+
var _chunk2IZ6S225js = require('./chunk-2IZ6S225.js');
|
|
7
|
+
require('./chunk-4CV4JOE5.js');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
exports.RiverbankEnvError = _chunk2IZ6S225js.RiverbankEnvError; exports.getRiverbankEnv = _chunk2IZ6S225js.getRiverbankEnv; exports.getRiverbankTarget = _chunk2IZ6S225js.getRiverbankTarget; exports.isPreviewMode = _chunk2IZ6S225js.isPreviewMode;
|
|
7
14
|
//# sourceMappingURL=env.js.map
|
package/dist/server/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/env.js"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,
|
|
1
|
+
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/env.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACF,qPAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/env.js"}
|
package/dist/server/env.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
RiverbankEnvError,
|
|
3
|
+
getRiverbankEnv,
|
|
4
|
+
getRiverbankTarget,
|
|
2
5
|
isPreviewMode
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PPHZV6YD.mjs";
|
|
7
|
+
import "./chunk-NFEGQTCC.mjs";
|
|
4
8
|
export {
|
|
9
|
+
RiverbankEnvError,
|
|
10
|
+
getRiverbankEnv,
|
|
11
|
+
getRiverbankTarget,
|
|
5
12
|
isPreviewMode
|
|
6
13
|
};
|
|
7
14
|
//# sourceMappingURL=env.mjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as LoadPageResult } from './loadPage-
|
|
2
|
-
import { S as SiteResponse } from './types-
|
|
1
|
+
import { a as LoadPageResult } from './loadPage-BucnLHmE.mjs';
|
|
2
|
+
import { S as SiteResponse } from './types-C-LShyIg.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Metadata generation helper for Next.js pages
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as LoadPageResult } from './loadPage-
|
|
2
|
-
import { S as SiteResponse } from './types-
|
|
1
|
+
import { a as LoadPageResult } from './loadPage-BmYJCe_V.js';
|
|
2
|
+
import { S as SiteResponse } from './types-BRQyLrQU.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Metadata generation helper for Next.js pages
|