     1	import { validateRelationships } from './lib/querying-writing/scope-validations.js'
     2	
     3	// Import hook functions
     4	import compileResourceSchemas from './rest-api-plugin-hooks/compile-resource-schemas.js'
     5	import validateIncludeConfigurations from './rest-api-plugin-hooks/validate-include-configurations.js'
     6	import turnScopeInitIntoVars from './rest-api-plugin-hooks/turn-scope-init-into-vars.js'
     7	import registerScopeRoutes from './rest-api-plugin-hooks/register-scope-routes.js'
     8	import registerRelationshipRoutes from './rest-api-plugin-hooks/register-relationship-routes.js'
     9	
    10	// Import method functions
    11	import queryMethod from './rest-api-plugin-methods/query.js'
    12	import getMethod from './rest-api-plugin-methods/get.js'
    13	import postMethod from './rest-api-plugin-methods/post.js'
    14	import putMethod from './rest-api-plugin-methods/put.js'
    15	import patchMethod from './rest-api-plugin-methods/patch.js'
    16	import deleteMethod from './rest-api-plugin-methods/delete.js'
    17	import enrichAttributesMethod from './rest-api-plugin-methods/enrich-attributes.js'
    18	import checkPermissionsMethod from './rest-api-plugin-methods/check-permissions.js'
    19	import addRouteMethod from './rest-api-plugin-methods/add-route.js'
    20	import releaseMethod from './rest-api-plugin-methods/release.js'
    21	import { defaultDataHelpers } from './lib/querying-writing/default-data-helpers.js'
    22	import { DEFAULT_QUERY_LIMIT, DEFAULT_MAX_QUERY_LIMIT, DEFAULT_INCLUDE_DEPTH_LIMIT } from './lib/querying-writing/knex-constants.js'
    23	
    24	import getRelatedMethod from './rest-api-plugin-methods/get-related.js'
    25	import postRelationshipMethod from './rest-api-plugin-methods/post-relationship.js'
    26	import getRelationshipMethod from './rest-api-plugin-methods/get-relationship.js'
    27	import patchRelationshipMethod from './rest-api-plugin-methods/patch-relationship.js'
    28	import deleteRelationshipMethod from './rest-api-plugin-methods/delete-relationship.js'
    29	
    30	export const RestApiPlugin = {
    31	  name: 'rest-api',
    32	
    33	  install ({ helpers, addScopeMethod, addApiMethod, vars, addHook, runHooks, apiOptions, pluginOptions, api, setScopeAlias, scopes, log, on }) {
    34	    // **************
    35	    // Initial setup
    36	    // **************
    37	
    38	    // Initialize the rest namespace for REST API functionality
    39	    api.rest = {}
    40	
    41	    // Set up REST-friendly aliases
    42	    setScopeAlias('resources', 'addResource')
    43	
    44	    // **********
    45	    // Variables
    46	    // **********
    47	
    48	    // Initialize default vars for the plugin from pluginOptions
    49	    const restApiOptions = pluginOptions || {}
    50	
    51	    // These will be used as default fallbacks by the vars proxy if
    52	    // they are not set in the scope options
    53	    vars.queryDefaultLimit = restApiOptions.queryDefaultLimit || DEFAULT_QUERY_LIMIT
    54	    vars.queryMaxLimit = restApiOptions.queryMaxLimit || DEFAULT_MAX_QUERY_LIMIT
    55	    vars.includeDepthLimit = restApiOptions.includeDepthLimit || DEFAULT_INCLUDE_DEPTH_LIMIT
    56	    vars.enablePaginationCounts = restApiOptions.enablePaginationCounts || true
    57	
    58	    // New simplified settings
    59	    vars.simplifiedTransport = restApiOptions.simplifiedTransport !== undefined
    60	      ? restApiOptions.simplifiedTransport
    61	      : false // Default false for JSON:API compliance over the wire
    62	
    63	    vars.simplifiedApi = restApiOptions.simplifiedApi !== undefined
    64	      ? restApiOptions.simplifiedApi
    65	      : true // Default true for better DX in programmatic API
    66	
    67	    vars.idProperty = restApiOptions.idProperty || 'id'
    68	
    69	    // Return full record configuration for API and Transport
    70	    // Support values: 'no', 'minimal', 'full'
    71	    const normalizeReturnValue = (value, defaultValue) => {
    72	      if (['no', 'minimal', 'full'].includes(value)) return value
    73	      return defaultValue
    74	    }
    75	
    76	    const optionConfigs = [
    77	      {
    78	        propName: 'returnRecordApi',
    79	        defaultValue: 'full',
    80	      },
    81	      {
    82	        propName: 'returnRecordTransport',
    83	        defaultValue: 'no',
    84	      },
    85	    ]
    86	
    87	    for (const config of optionConfigs) {
    88	      const optionValue = restApiOptions[config.propName]
    89	      let processedValue
    90	
    91	      if (typeof optionValue === 'object' && optionValue !== null) {
    92	        processedValue = {
    93	          post: normalizeReturnValue(optionValue.post, config.defaultValue),
    94	          put: normalizeReturnValue(optionValue.put, config.defaultValue),
    95	          patch: normalizeReturnValue(optionValue.patch, config.defaultValue),
    96	        }
    97	      } else if (optionValue !== undefined) {
    98	        const normalized = normalizeReturnValue(optionValue, config.defaultValue)
    99	        processedValue = { post: normalized, put: normalized, patch: normalized }
   100	      } else {
   101	        processedValue = { post: config.defaultValue, put: config.defaultValue, patch: config.defaultValue }
   102	      }
   103	      vars[config.propName] = processedValue
   104	    }
   105	
   106	    log.debug('returnRecordApi configuration:', vars.returnRecordApi)
   107	    log.debug('returnRecordTransport configuration:', vars.returnRecordTransport)
   108	
   109	    // Schema cache vars
   110	    vars.schemaProcessed = false
   111	    vars.schema = null
   112	
   113	    // ******************************
   114	    // Scope (resources) added hooks
   115	    // ******************************
   116	
   117	    addHook('scope:added', 'validateRelationships', {}, validateRelationships)
   118	    addHook('scope:added', 'compileResourceSchemas', {}, compileResourceSchemas)
   119	    addHook('scope:added', 'validateIncludeConfigurations', {}, validateIncludeConfigurations)
   120	    addHook('scope:added', 'turnScopeInitIntoVars', {}, turnScopeInitIntoVars)
   121	
   122	    // *********
   123	    // Methods
   124	    // *********
   125	
   126	    addApiMethod('addRoute', addRouteMethod)
   127	
   128	    addApiMethod('release', releaseMethod)
   129	
   130	    // Main REST methods
   131	    addScopeMethod('query', queryMethod)
   132	    addScopeMethod('get', getMethod)
   133	    addScopeMethod('post', postMethod)
   134	    addScopeMethod('put', putMethod)
   135	    addScopeMethod('patch', patchMethod)
   136	    addScopeMethod('delete', deleteMethod)
   137	
   138	    // Relationship methods
   139	    addScopeMethod('getRelationship', getRelationshipMethod)
   140	    addScopeMethod('getRelated', getRelatedMethod)
   141	    addScopeMethod('postRelationship', postRelationshipMethod)
   142	    addScopeMethod('patchRelationship', patchRelationshipMethod)
   143	    addScopeMethod('deleteRelationship', deleteRelationshipMethod)
   144	
   145	    addHook('scope:added', 'registerRelationshipRoutes', {}, registerRelationshipRoutes)
   146	    addHook('scope:added', 'registerScopeRoutes', {}, registerScopeRoutes)
   147	
   148	    // Non-URL methods
   149	    addScopeMethod('enrichAttributes', enrichAttributesMethod)
   150	    addScopeMethod('checkPermissions', checkPermissionsMethod)
   151	
   152	    // *********
   153	    // Helpers
   154	    // *********
   155	
   156	    // Initialize default data helpers that throw errors until a storage plugin is installed
   157	    // These placeholders show storage plugin developers what methods to implement
   158	    // Example: helpers.dataGet, helpers.dataPost, etc. will throw "No storage implementation" errors
   159	    Object.assign(helpers, defaultDataHelpers)
   160	
   161	    // Add default getLocation helper for generating resource URLs
   162	    // This can be overridden by storage plugins if needed
   163	    helpers.getLocation = ({ scopeName, id }) => `/${scopeName}/${id}`
   164	  }
   165	}
