@collective-intelligence/external-apps-server-sdk 0.1.2 → 0.1.4
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 +86 -0
- package/dist/admin.js +2 -2
- package/dist/auth/better-auth.js +1 -1
- package/dist/auth/federated.d.ts +66 -0
- package/dist/auth/federated.js +4 -4
- package/dist/auth.js +1 -1
- package/dist/express.js +1 -1
- package/dist/gateway.js +4 -4
- package/dist/index.js +6 -6
- package/dist/knowledge-sources/payload.js +1 -1
- package/dist/knowledge-sources/strapi.js +1 -1
- package/dist/persistence/drizzle-effect.js +1 -1
- package/dist/persistence/drizzle.js +8 -8
- package/dist/resources.js +7 -7
- package/dist/runtime/effect.js +7 -7
- package/dist/runtime/express.js +1 -1
- package/dist/runtime/nestjs.js +4 -4
- package/dist/runtime/next.js +4 -4
- package/dist/runtime/web.js +4 -4
- package/dist/tools/ai-sdk.js +4 -4
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true,configurable:true,set:__exportSetter.bind(all,name)})};var exports_payload={};__export(exports_payload,{definePayloadSource:()=>definePayloadSource,definePayloadGlobalSource:()=>definePayloadGlobalSource,definePayloadGatewayPlugin:()=>definePayloadGatewayPlugin});var resourceCapabilityByOperation={create:"create",get:"get",hard_delete:"hardDelete",list:"search",restore:"restore",soft_delete:"softDelete",update:"update"};class DataSourceMappingError extends TypeError{code;constructor(code,message){super(message);this.name="DataSourceMappingError";this.code=code}}var isJsonValue=(value)=>{if(value===null||typeof value==="boolean"||typeof value==="number"||typeof value==="string"){return true}if(Array.isArray(value)){return value.every(isJsonValue)}if(typeof value!=="object"||value===null){return false}const prototype=Object.getPrototypeOf(value);if(prototype!==Object.prototype&&prototype!==null){return false}return Object.values(value).every(isJsonValue)};var parseJsonValue=(value)=>{if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping","Value must be JSON-compatible")}return value};var encode=(prefix,value)=>`${prefix}.${Buffer.from(JSON.stringify(value)).toString("base64url")}`;var decode=(prefix,value)=>{if(!value.startsWith(`${prefix}.`)){throw new DataSourceMappingError("invalid_identity",`Expected an opaque ${prefix} identifier`)}try{const parsed=JSON.parse(Buffer.from(value.slice(prefix.length+1),"base64url").toString("utf-8"));if(!isJsonValue(parsed)){throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}return parsed}catch{throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}};var opaqueIdentity=(kind,fields,record)=>{const values=fields.map((field)=>{const value=record[field];if(typeof value!=="string"&&typeof value!=="number"){throw new DataSourceMappingError("invalid_identity",`Identity field ${field} must be a string or number`)}return value});return encode(`${kind}:id`,values)};var decodeIdentity=(kind,fields,id)=>{const values=decode(`${kind}:id`,id);if(!Array.isArray(values)||values.length!==fields.length){throw new DataSourceMappingError("invalid_identity","Opaque identifier does not match the configured identity")}return Object.fromEntries(fields.map((field,index)=>[field,values[index]]))};var opaqueRevision=(kind,revision)=>encode(`${kind}:rev`,revision);var nativeIdentifier=(value)=>{if(typeof value!=="string"&&typeof value!=="number"){throw new DataSourceMappingError("invalid_identity","Identity value must be a string or number")}return value};var optionalNativeString=(value)=>typeof value==="string"?value:undefined;var cursor=(kind,value)=>encode(`${kind}:cursor`,value);var decodeCursor=(kind,value)=>decode(`${kind}:cursor`,value);var projectedRelation=(kind,relation,value)=>{const normalize=(record)=>{if(typeof record!=="object"||record===null){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an object identity`)}const nativeRecord=Object.fromEntries(Object.entries(record));return opaqueIdentity(`${kind}:${relation.targetResourceId}`,relation.targetIdentityFields,nativeRecord)};if(relation.cardinality==="many"){if(!Array.isArray(value)){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an array`)}return value.map(normalize)}return value===null||value===undefined?null:normalize(value)};var project=(kind,projection,row)=>{const redacted=new Set(projection.redact);const relations=new Map((projection.relations??[]).map((relation)=>[relation.field,relation]));const entries=[];for(const field of projection.fields){if(redacted.has(field)){continue}const value=row[field];const relation=relations.get(field);if(relation!==undefined){entries.push([field,projectedRelation(kind,relation,value)]);continue}if(value===undefined){continue}if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping",`Field ${field} is not JSON-compatible`)}entries.push([field,value])}return Object.fromEntries(entries)};var record=(kind,options,row)=>{const deletedAt=options.softDelete?.deletedAt(row);const result={id:opaqueIdentity(kind,options.identity.fields,row),revision:opaqueRevision(kind,options.revision(row)),value:project(kind,options.projection,row)};if(deletedAt!==undefined){result.deletedAt=deletedAt}return result};var success=(correlationId,value)=>({correlationId,ok:true,value});var failure=(correlationId,error)=>({correlationId,error,ok:false});var nativeFilterOperator=(operator)=>operator.replaceAll(/_(?<letter>[a-z])/gu,(_match,letter)=>letter.toUpperCase());var unsupportedOperation=(correlationId,capabilities,operation)=>{const capability=resourceCapabilityByOperation[operation];if(capabilities[capability]===true){return}return failure(correlationId,{code:"capability_not_supported",details:{capability},message:`The data source does not support ${capability}`,retryable:false})};var conflict=(correlationId)=>failure(correlationId,{code:"conflict",message:"The expected revision does not match the current record",retryable:false});var invalid=(correlationId,cause)=>failure(correlationId,{code:"invalid_request",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The data-source request is invalid",retryable:false});var nativeFailure=(correlationId,cause)=>failure(correlationId,{code:"internal",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The native data source failed",retryable:false});var assertConfiguration=(options)=>{const fields=[...options.projection.fields,...options.projection.redact??[]];if(new Set(fields).size!==fields.length){throw new DataSourceMappingError("duplicate_field","Exposed and redacted fields must be disjoint and unique")}const maxPageSize=options.maxPageSize??100;if(!Number.isSafeInteger(maxPageSize)||maxPageSize<1){throw new DataSourceMappingError("invalid_pagination","maxPageSize must be a positive safe integer")}if(options.capabilities.pagination.length===0){throw new DataSourceMappingError("invalid_pagination","At least one pagination mode must be declared")}const declaredPagination=new Set(options.definition.query.pagination.modes);if(declaredPagination.size!==options.capabilities.pagination.length||options.capabilities.pagination.some((mode)=>!declaredPagination.has(mode))){throw new DataSourceMappingError("capability_mismatch","Data-source pagination must match the resource definition")}if(options.capabilities.relations!==(options.projection.relations?.length??0)>0){throw new DataSourceMappingError("capability_mismatch","Relation capability must match the explicit relation projection")}for(const capability of["create","hardDelete","restore","softDelete","update"]){if(options.capabilities[capability]!==(options.definition.capabilities[capability]===true)){throw new DataSourceMappingError("capability_mismatch",`${capability} capability must match the resource definition`)}}};var boundedLimit=(requested,maximum=100)=>{if(!Number.isSafeInteger(requested)||requested<1){throw new DataSourceMappingError("invalid_pagination","Page size must be a positive safe integer")}return Math.min(requested,maximum)};var expectedRevisionMatches=(kind,options,row,expectedRevision)=>opaqueRevision(kind,options.revision(row))===expectedRevision;var kind="payload";var optionalProperty=(key,value)=>value===undefined?{}:{[key]:value};var payloadWhere=(filter)=>{if(filter===undefined){return}if("filters"in filter){const filters=filter.filters.map(payloadWhere).filter((where)=>where!==undefined);return{[filter.operator]:filters}}if("filter"in filter){const nested=payloadWhere(filter.filter);return nested===undefined?undefined:{not:nested}}if(filter.operator==="is_null"){return{[filter.field]:{exists:false}}}if(filter.operator==="is_not_null"){return{[filter.field]:{exists:true}}}if(!("value"in filter)){return}const{operator:filterOperator,value:filterValue}=filter;const operator=nativeFilterOperator(filterOperator);let patternValue;if(filterOperator==="starts_with"||filterOperator==="ends_with"){try{patternValue=String(nativeIdentifier(filterValue))}catch{throw new TypeError(`${filterOperator} requires a string or number`)}}if((filterOperator==="starts_with"||filterOperator==="ends_with")&&patternValue===undefined){throw new TypeError(`${filterOperator} requires a string or number`)}let value;if(filterOperator==="starts_with"){value=`${patternValue}%`}else if(filterOperator==="ends_with"){value=`%${patternValue}`}else{value=filterValue}return{[filter.field]:{[operator]:value}}};var nativeId=(options,identity)=>{const[firstField]=options.identity.fields;return nativeIdentifier(identity[firstField])};var localeFor=(options,identity)=>{if(options.localeField!==undefined&&identity!==undefined){const value=identity[options.localeField];const localeValue=optionalNativeString(value);if(localeValue!==undefined){return localeValue}}return options.locale};var validatePayload=(options)=>{if(!options.capabilities.nativePolicy){throw new TypeError("Payload must declare nativePolicy support")}if(options.capabilities.transactions||options.capabilities.softDelete!==(options.softDelete!==undefined)){throw new TypeError("Payload transaction and soft-delete capabilities require explicit policy")}if(options.capabilities.hardDelete!==(options.plugin?.hardDelete!==undefined)||options.capabilities.restore!==(options.plugin?.restore!==undefined)||options.capabilities.incrementalChanges!==(options.plugin?.changes!==undefined)){throw new TypeError("Payload capabilities must match installed plugin hooks")}if(options.capabilities.softDelete!==(options.definition.capabilities.softDelete===true)){throw new TypeError("Payload soft-delete capability must match its resource definition")}};var definePayloadSource=(options)=>{assertConfiguration(options);validatePayload(options);const maximum=options.maxPageSize??100;const executeList=async(request,callContext,draft)=>{const{pagination}=request.query;let page=1;if(pagination.mode==="page"){const{page:requestedPage}=pagination;page=requestedPage}else if(pagination.cursor!==undefined){page=decodeCursor(kind,pagination.cursor)}const pageSize=boundedLimit(pagination.mode==="page"?pagination.pageSize:pagination.limit,maximum);const result=await options.local.find({...callContext,collection:options.collection,draft,limit:pageSize,...optionalProperty("locale",options.locale),page,...optionalProperty("sort",request.query.sort?.map((sort)=>sort.direction==="desc"?`-${sort.field}`:sort.field)),...optionalProperty("where",payloadWhere(request.query.filter))});const items=result.docs.map((row)=>record(kind,options,row));if(pagination.mode==="page"){return success(request.requestId,{items,page,pageSize,pagination:"page",totalItems:result.totalDocs,totalPages:result.totalPages})}return success(request.requestId,{items,...optionalProperty("nextCursor",page>=result.totalPages?undefined:cursor(kind,page+1)),pagination:"cursor"})};const executeCreate=async(request,callContext,draft)=>{const row=await options.local.create({...callContext,collection:options.collection,data:parseJsonValue(request.value),draft,...optionalProperty("locale",options.locale)});return success(request.requestId,record(kind,options,row))};const execute=async(request,context,requestOptions)=>{const unsupported=unsupportedOperation(request.requestId,options.definition.capabilities,request.operation);if(unsupported!==undefined){return unsupported}const user=options.user(context);const callContext={overrideAccess:false,...optionalProperty("req",options.nativeRequest?.(context)),user};const draft=options.includeDrafts===true;try{if(request.operation==="list"){return await executeList(request,callContext,draft)}if(request.operation==="create"){return await executeCreate(request,callContext,draft)}const identity=decodeIdentity(kind,options.identity.fields,request.id);const id=nativeId(options,identity);const locale=localeFor(options,identity);const current=await options.local.findByID({...callContext,collection:options.collection,draft,id,...optionalProperty("locale",locale)});if(current===null){return{correlationId:request.requestId,error:{code:"not_found",message:"The Payload document was not found",retryable:false},ok:false}}if(request.operation==="get"){return success(request.requestId,record(kind,options,current))}if(!expectedRevisionMatches(kind,options,current,request.expectedRevision)){return conflict(request.requestId)}if(request.operation==="update"){const row2=await options.local.update({...callContext,collection:options.collection,data:parseJsonValue(request.value),draft,id,...optionalProperty("locale",locale)});return success(request.requestId,record(kind,options,row2))}if(request.operation==="hard_delete"){await options.plugin?.hardDelete?.({collection:options.collection,id,...optionalProperty("locale",locale),organizationId:context.organizationId,...optionalProperty("signal",requestOptions?.signal),user});return success(request.requestId,null)}if(request.operation==="restore"){const row2=await options.plugin?.restore?.({collection:options.collection,id,...optionalProperty("locale",locale),organizationId:context.organizationId,...optionalProperty("signal",requestOptions?.signal),user});if(row2===undefined){throw new TypeError("Restore is not supported")}return success(request.requestId,record(kind,options,row2))}const row=await options.local.delete({...callContext,collection:options.collection,id,...optionalProperty("locale",locale)});return success(request.requestId,record(kind,options,row))}catch(error){return error instanceof TypeError?invalid(request.requestId,error):nativeFailure(request.requestId,error)}};const changes=options.plugin?.changes===undefined?undefined:async(request,context,requestOptions)=>{try{const after=request.cursor===undefined?undefined:decodeCursor(`${kind}:changes`,request.cursor);const user=options.user(context);const page=await options.plugin?.changes?.({...optionalProperty("after",after),collection:options.collection,limit:boundedLimit(request.limit,maximum),...optionalProperty("locale",options.locale),organizationId:context.organizationId,overlapMs:options.incrementalChanges?.overlapMs??5000,...optionalProperty("signal",requestOptions?.signal),user});if(page===undefined){throw new TypeError("Changes are unavailable")}const projectedChanges=page.changes.map((change)=>change.kind==="upsert"?{kind:"upsert",record:record(kind,options,change.row)}:{deletedAt:change.deletedAt,id:opaqueIdentity(kind,options.identity.fields,change.identity),kind:"tombstone",revision:opaqueRevision(kind,change.revision)});const final=page.changes.at(-1);const nextCursor=final===undefined?undefined:cursor(`${kind}:changes`,{externalId:final.kind==="upsert"?opaqueIdentity(kind,options.identity.fields,final.row):opaqueIdentity(kind,options.identity.fields,final.identity),updatedAt:final.kind==="upsert"?options.updatedAt(final.row):final.updatedAt});return success(request.requestId,{changes:projectedChanges,...optionalProperty("nextCursor",nextCursor)})}catch(error){return invalid(request.requestId,error)}};const source={authorization:options.authorization,...optionalProperty("changes",changes),dataSource:{capabilities:options.capabilities,kind},definition:options.definition,execute};return Object.freeze(source)};var definePayloadGlobalSource=(options)=>{assertConfiguration(options);if(!options.capabilities.nativePolicy){throw new TypeError("Payload must declare nativePolicy support")}if(options.capabilities.create||options.capabilities.hardDelete||options.capabilities.incrementalChanges||options.capabilities.restore||options.capabilities.softDelete||options.capabilities.transactions){throw new TypeError("Payload globals only support read and update")}const load=async(context)=>await options.local.findGlobal({draft:options.includeDrafts===true,...optionalProperty("locale",options.locale),overrideAccess:false,...optionalProperty("req",options.nativeRequest?.(context)),slug:options.global,user:options.user(context)});const execute=async(request,context)=>{const unsupported=unsupportedOperation(request.requestId,options.definition.capabilities,request.operation);if(unsupported!==undefined){return unsupported}try{const current=await load(context);if(request.operation==="list"){return success(request.requestId,{items:[record(kind,options,current)],...request.query.pagination.mode==="page"?{page:request.query.pagination.page,pageSize:request.query.pagination.pageSize,pagination:"page",totalItems:1,totalPages:1}:{pagination:"cursor"}})}const currentRecord=record(kind,options,current);if(request.operation==="get"){if(request.id!==currentRecord.id){return{correlationId:request.requestId,error:{code:"not_found",message:"The Payload global was not found",retryable:false},ok:false}}return success(request.requestId,currentRecord)}if(request.operation!=="update"){return invalid(request.requestId,new TypeError("Unsupported Payload global operation"))}if(!expectedRevisionMatches(kind,options,current,request.expectedRevision)){return conflict(request.requestId)}const updated=await options.local.updateGlobal({data:parseJsonValue(request.value),draft:options.includeDrafts===true,...optionalProperty("locale",options.locale),overrideAccess:false,...optionalProperty("req",options.nativeRequest?.(context)),slug:options.global,user:options.user(context)});return success(request.requestId,record(kind,options,updated))}catch(error){return error instanceof TypeError?invalid(request.requestId,error):nativeFailure(request.requestId,error)}};return Object.freeze({authorization:options.authorization,dataSource:{capabilities:options.capabilities,kind},definition:options.definition,execute})};var definePayloadGatewayPlugin=(hooks)=>Object.freeze(hooks);var{definePayloadGatewayPlugin:definePayloadGatewayPlugin2,definePayloadGlobalSource:definePayloadGlobalSource2,definePayloadSource:definePayloadSource2}=exports_payload;export{definePayloadSource2 as definePayloadSource,definePayloadGlobalSource2 as definePayloadGlobalSource,definePayloadGatewayPlugin2 as definePayloadGatewayPlugin};
|
|
1
|
+
var __defProp=Object.defineProperty;var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true,configurable:true,set:__exportSetter.bind(all,name)})};var exports_payload={};__export(exports_payload,{definePayloadGatewayPlugin:()=>definePayloadGatewayPlugin,definePayloadGlobalSource:()=>definePayloadGlobalSource,definePayloadSource:()=>definePayloadSource});var resourceCapabilityByOperation={create:"create",get:"get",hard_delete:"hardDelete",list:"search",restore:"restore",soft_delete:"softDelete",update:"update"};class DataSourceMappingError extends TypeError{code;constructor(code,message){super(message);this.name="DataSourceMappingError";this.code=code}}var isJsonValue=(value)=>{if(value===null||typeof value==="boolean"||typeof value==="number"||typeof value==="string"){return true}if(Array.isArray(value)){return value.every(isJsonValue)}if(typeof value!=="object"||value===null){return false}const prototype=Object.getPrototypeOf(value);if(prototype!==Object.prototype&&prototype!==null){return false}return Object.values(value).every(isJsonValue)};var parseJsonValue=(value)=>{if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping","Value must be JSON-compatible")}return value};var encode=(prefix,value)=>`${prefix}.${Buffer.from(JSON.stringify(value)).toString("base64url")}`;var decode=(prefix,value)=>{if(!value.startsWith(`${prefix}.`)){throw new DataSourceMappingError("invalid_identity",`Expected an opaque ${prefix} identifier`)}try{const parsed=JSON.parse(Buffer.from(value.slice(prefix.length+1),"base64url").toString("utf-8"));if(!isJsonValue(parsed)){throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}return parsed}catch{throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}};var opaqueIdentity=(kind,fields,record)=>{const values=fields.map((field)=>{const value=record[field];if(typeof value!=="string"&&typeof value!=="number"){throw new DataSourceMappingError("invalid_identity",`Identity field ${field} must be a string or number`)}return value});return encode(`${kind}:id`,values)};var decodeIdentity=(kind,fields,id)=>{const values=decode(`${kind}:id`,id);if(!Array.isArray(values)||values.length!==fields.length){throw new DataSourceMappingError("invalid_identity","Opaque identifier does not match the configured identity")}return Object.fromEntries(fields.map((field,index)=>[field,values[index]]))};var opaqueRevision=(kind,revision)=>encode(`${kind}:rev`,revision);var nativeIdentifier=(value)=>{if(typeof value!=="string"&&typeof value!=="number"){throw new DataSourceMappingError("invalid_identity","Identity value must be a string or number")}return value};var optionalNativeString=(value)=>typeof value==="string"?value:undefined;var cursor=(kind,value)=>encode(`${kind}:cursor`,value);var decodeCursor=(kind,value)=>decode(`${kind}:cursor`,value);var projectedRelation=(kind,relation,value)=>{const normalize=(record)=>{if(typeof record!=="object"||record===null){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an object identity`)}const nativeRecord=Object.fromEntries(Object.entries(record));return opaqueIdentity(`${kind}:${relation.targetResourceId}`,relation.targetIdentityFields,nativeRecord)};if(relation.cardinality==="many"){if(!Array.isArray(value)){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an array`)}return value.map(normalize)}return value===null||value===undefined?null:normalize(value)};var project=(kind,projection,row)=>{const redacted=new Set(projection.redact);const relations=new Map((projection.relations??[]).map((relation)=>[relation.field,relation]));const entries=[];for(const field of projection.fields){if(redacted.has(field)){continue}const value=row[field];const relation=relations.get(field);if(relation!==undefined){entries.push([field,projectedRelation(kind,relation,value)]);continue}if(value===undefined){continue}if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping",`Field ${field} is not JSON-compatible`)}entries.push([field,value])}return Object.fromEntries(entries)};var record=(kind,options,row)=>{const deletedAt=options.softDelete?.deletedAt(row);const result={id:opaqueIdentity(kind,options.identity.fields,row),revision:opaqueRevision(kind,options.revision(row)),value:project(kind,options.projection,row)};if(deletedAt!==undefined){result.deletedAt=deletedAt}return result};var success=(correlationId,value)=>({correlationId,ok:true,value});var failure=(correlationId,error)=>({correlationId,error,ok:false});var nativeFilterOperator=(operator)=>operator.replaceAll(/_(?<letter>[a-z])/gu,(_match,letter)=>letter.toUpperCase());var unsupportedOperation=(correlationId,capabilities,operation)=>{const capability=resourceCapabilityByOperation[operation];if(capabilities[capability]===true){return}return failure(correlationId,{code:"capability_not_supported",details:{capability},message:`The data source does not support ${capability}`,retryable:false})};var conflict=(correlationId)=>failure(correlationId,{code:"conflict",message:"The expected revision does not match the current record",retryable:false});var invalid=(correlationId,cause)=>failure(correlationId,{code:"invalid_request",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The data-source request is invalid",retryable:false});var nativeFailure=(correlationId,cause)=>failure(correlationId,{code:"internal",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The native data source failed",retryable:false});var assertConfiguration=(options)=>{const fields=[...options.projection.fields,...options.projection.redact??[]];if(new Set(fields).size!==fields.length){throw new DataSourceMappingError("duplicate_field","Exposed and redacted fields must be disjoint and unique")}const maxPageSize=options.maxPageSize??100;if(!Number.isSafeInteger(maxPageSize)||maxPageSize<1){throw new DataSourceMappingError("invalid_pagination","maxPageSize must be a positive safe integer")}if(options.capabilities.pagination.length===0){throw new DataSourceMappingError("invalid_pagination","At least one pagination mode must be declared")}const declaredPagination=new Set(options.definition.query.pagination.modes);if(declaredPagination.size!==options.capabilities.pagination.length||options.capabilities.pagination.some((mode)=>!declaredPagination.has(mode))){throw new DataSourceMappingError("capability_mismatch","Data-source pagination must match the resource definition")}if(options.capabilities.relations!==(options.projection.relations?.length??0)>0){throw new DataSourceMappingError("capability_mismatch","Relation capability must match the explicit relation projection")}for(const capability of["create","hardDelete","restore","softDelete","update"]){if(options.capabilities[capability]!==(options.definition.capabilities[capability]===true)){throw new DataSourceMappingError("capability_mismatch",`${capability} capability must match the resource definition`)}}};var boundedLimit=(requested,maximum=100)=>{if(!Number.isSafeInteger(requested)||requested<1){throw new DataSourceMappingError("invalid_pagination","Page size must be a positive safe integer")}return Math.min(requested,maximum)};var expectedRevisionMatches=(kind,options,row,expectedRevision)=>opaqueRevision(kind,options.revision(row))===expectedRevision;var kind="payload";var optionalProperty=(key,value)=>value===undefined?{}:{[key]:value};var payloadWhere=(filter)=>{if(filter===undefined){return}if("filters"in filter){const filters=filter.filters.map(payloadWhere).filter((where)=>where!==undefined);return{[filter.operator]:filters}}if("filter"in filter){const nested=payloadWhere(filter.filter);return nested===undefined?undefined:{not:nested}}if(filter.operator==="is_null"){return{[filter.field]:{exists:false}}}if(filter.operator==="is_not_null"){return{[filter.field]:{exists:true}}}if(!("value"in filter)){return}const{operator:filterOperator,value:filterValue}=filter;const operator=nativeFilterOperator(filterOperator);let patternValue;if(filterOperator==="starts_with"||filterOperator==="ends_with"){try{patternValue=String(nativeIdentifier(filterValue))}catch{throw new TypeError(`${filterOperator} requires a string or number`)}}if((filterOperator==="starts_with"||filterOperator==="ends_with")&&patternValue===undefined){throw new TypeError(`${filterOperator} requires a string or number`)}let value;if(filterOperator==="starts_with"){value=`${patternValue}%`}else if(filterOperator==="ends_with"){value=`%${patternValue}`}else{value=filterValue}return{[filter.field]:{[operator]:value}}};var nativeId=(options,identity)=>{const[firstField]=options.identity.fields;return nativeIdentifier(identity[firstField])};var localeFor=(options,identity)=>{if(options.localeField!==undefined&&identity!==undefined){const value=identity[options.localeField];const localeValue=optionalNativeString(value);if(localeValue!==undefined){return localeValue}}return options.locale};var validatePayload=(options)=>{if(!options.capabilities.nativePolicy){throw new TypeError("Payload must declare nativePolicy support")}if(options.capabilities.transactions||options.capabilities.softDelete!==(options.softDelete!==undefined)){throw new TypeError("Payload transaction and soft-delete capabilities require explicit policy")}if(options.capabilities.hardDelete!==(options.plugin?.hardDelete!==undefined)||options.capabilities.restore!==(options.plugin?.restore!==undefined)||options.capabilities.incrementalChanges!==(options.plugin?.changes!==undefined)){throw new TypeError("Payload capabilities must match installed plugin hooks")}if(options.capabilities.softDelete!==(options.definition.capabilities.softDelete===true)){throw new TypeError("Payload soft-delete capability must match its resource definition")}};var definePayloadSource=(options)=>{assertConfiguration(options);validatePayload(options);const maximum=options.maxPageSize??100;const executeList=async(request,callContext,draft)=>{const{pagination}=request.query;let page=1;if(pagination.mode==="page"){const{page:requestedPage}=pagination;page=requestedPage}else if(pagination.cursor!==undefined){page=decodeCursor(kind,pagination.cursor)}const pageSize=boundedLimit(pagination.mode==="page"?pagination.pageSize:pagination.limit,maximum);const result=await options.local.find({...callContext,collection:options.collection,draft,limit:pageSize,...optionalProperty("locale",options.locale),page,...optionalProperty("sort",request.query.sort?.map((sort)=>sort.direction==="desc"?`-${sort.field}`:sort.field)),...optionalProperty("where",payloadWhere(request.query.filter))});const items=result.docs.map((row)=>record(kind,options,row));if(pagination.mode==="page"){return success(request.requestId,{items,page,pageSize,pagination:"page",totalItems:result.totalDocs,totalPages:result.totalPages})}return success(request.requestId,{items,...optionalProperty("nextCursor",page>=result.totalPages?undefined:cursor(kind,page+1)),pagination:"cursor"})};const executeCreate=async(request,callContext,draft)=>{const row=await options.local.create({...callContext,collection:options.collection,data:parseJsonValue(request.value),draft,...optionalProperty("locale",options.locale)});return success(request.requestId,record(kind,options,row))};const execute=async(request,context,requestOptions)=>{const unsupported=unsupportedOperation(request.requestId,options.definition.capabilities,request.operation);if(unsupported!==undefined){return unsupported}const user=options.user(context);const callContext={overrideAccess:false,...optionalProperty("req",options.nativeRequest?.(context)),user};const draft=options.includeDrafts===true;try{if(request.operation==="list"){return await executeList(request,callContext,draft)}if(request.operation==="create"){return await executeCreate(request,callContext,draft)}const identity=decodeIdentity(kind,options.identity.fields,request.id);const id=nativeId(options,identity);const locale=localeFor(options,identity);const current=await options.local.findByID({...callContext,collection:options.collection,draft,id,...optionalProperty("locale",locale)});if(current===null){return{correlationId:request.requestId,error:{code:"not_found",message:"The Payload document was not found",retryable:false},ok:false}}if(request.operation==="get"){return success(request.requestId,record(kind,options,current))}if(!expectedRevisionMatches(kind,options,current,request.expectedRevision)){return conflict(request.requestId)}if(request.operation==="update"){const row=await options.local.update({...callContext,collection:options.collection,data:parseJsonValue(request.value),draft,id,...optionalProperty("locale",locale)});return success(request.requestId,record(kind,options,row))}if(request.operation==="hard_delete"){await options.plugin?.hardDelete?.({collection:options.collection,id,...optionalProperty("locale",locale),organizationId:context.organizationId,...optionalProperty("signal",requestOptions?.signal),user});return success(request.requestId,null)}if(request.operation==="restore"){const row=await options.plugin?.restore?.({collection:options.collection,id,...optionalProperty("locale",locale),organizationId:context.organizationId,...optionalProperty("signal",requestOptions?.signal),user});if(row===undefined){throw new TypeError("Restore is not supported")}return success(request.requestId,record(kind,options,row))}const row=await options.local.delete({...callContext,collection:options.collection,id,...optionalProperty("locale",locale)});return success(request.requestId,record(kind,options,row))}catch(error){return error instanceof TypeError?invalid(request.requestId,error):nativeFailure(request.requestId,error)}};const changes=options.plugin?.changes===undefined?undefined:async(request,context,requestOptions)=>{try{const after=request.cursor===undefined?undefined:decodeCursor(`${kind}:changes`,request.cursor);const user=options.user(context);const page=await options.plugin?.changes?.({...optionalProperty("after",after),collection:options.collection,limit:boundedLimit(request.limit,maximum),...optionalProperty("locale",options.locale),organizationId:context.organizationId,overlapMs:options.incrementalChanges?.overlapMs??5000,...optionalProperty("signal",requestOptions?.signal),user});if(page===undefined){throw new TypeError("Changes are unavailable")}const projectedChanges=page.changes.map((change)=>change.kind==="upsert"?{kind:"upsert",record:record(kind,options,change.row)}:{deletedAt:change.deletedAt,id:opaqueIdentity(kind,options.identity.fields,change.identity),kind:"tombstone",revision:opaqueRevision(kind,change.revision)});const final=page.changes.at(-1);const nextCursor=final===undefined?undefined:cursor(`${kind}:changes`,{externalId:final.kind==="upsert"?opaqueIdentity(kind,options.identity.fields,final.row):opaqueIdentity(kind,options.identity.fields,final.identity),updatedAt:final.kind==="upsert"?options.updatedAt(final.row):final.updatedAt});return success(request.requestId,{changes:projectedChanges,...optionalProperty("nextCursor",nextCursor)})}catch(error){return invalid(request.requestId,error)}};const source={authorization:options.authorization,...optionalProperty("changes",changes),dataSource:{capabilities:options.capabilities,kind},definition:options.definition,execute};return Object.freeze(source)};var definePayloadGlobalSource=(options)=>{assertConfiguration(options);if(!options.capabilities.nativePolicy){throw new TypeError("Payload must declare nativePolicy support")}if(options.capabilities.create||options.capabilities.hardDelete||options.capabilities.incrementalChanges||options.capabilities.restore||options.capabilities.softDelete||options.capabilities.transactions){throw new TypeError("Payload globals only support read and update")}const load=async(context)=>await options.local.findGlobal({draft:options.includeDrafts===true,...optionalProperty("locale",options.locale),overrideAccess:false,...optionalProperty("req",options.nativeRequest?.(context)),slug:options.global,user:options.user(context)});const execute=async(request,context)=>{const unsupported=unsupportedOperation(request.requestId,options.definition.capabilities,request.operation);if(unsupported!==undefined){return unsupported}try{const current=await load(context);if(request.operation==="list"){return success(request.requestId,{items:[record(kind,options,current)],...request.query.pagination.mode==="page"?{page:request.query.pagination.page,pageSize:request.query.pagination.pageSize,pagination:"page",totalItems:1,totalPages:1}:{pagination:"cursor"}})}const currentRecord=record(kind,options,current);if(request.operation==="get"){if(request.id!==currentRecord.id){return{correlationId:request.requestId,error:{code:"not_found",message:"The Payload global was not found",retryable:false},ok:false}}return success(request.requestId,currentRecord)}if(request.operation!=="update"){return invalid(request.requestId,new TypeError("Unsupported Payload global operation"))}if(!expectedRevisionMatches(kind,options,current,request.expectedRevision)){return conflict(request.requestId)}const updated=await options.local.updateGlobal({data:parseJsonValue(request.value),draft:options.includeDrafts===true,...optionalProperty("locale",options.locale),overrideAccess:false,...optionalProperty("req",options.nativeRequest?.(context)),slug:options.global,user:options.user(context)});return success(request.requestId,record(kind,options,updated))}catch(error){return error instanceof TypeError?invalid(request.requestId,error):nativeFailure(request.requestId,error)}};return Object.freeze({authorization:options.authorization,dataSource:{capabilities:options.capabilities,kind},definition:options.definition,execute})};var definePayloadGatewayPlugin=(hooks)=>Object.freeze(hooks);var{definePayloadGatewayPlugin:definePayloadGatewayPlugin2,definePayloadGlobalSource:definePayloadGlobalSource2,definePayloadSource:definePayloadSource2}=exports_payload;export{definePayloadGatewayPlugin2 as definePayloadGatewayPlugin,definePayloadGlobalSource2 as definePayloadGlobalSource,definePayloadSource2 as definePayloadSource};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true,configurable:true,set:__exportSetter.bind(all,name)})};var exports_strapi={};__export(exports_strapi,{defineStrapiSource:()=>defineStrapiSource,defineStrapiGatewayPlugin:()=>defineStrapiGatewayPlugin});var resourceCapabilityByOperation={create:"create",get:"get",hard_delete:"hardDelete",list:"search",restore:"restore",soft_delete:"softDelete",update:"update"};class DataSourceMappingError extends TypeError{code;constructor(code,message){super(message);this.name="DataSourceMappingError";this.code=code}}var isJsonValue=(value)=>{if(value===null||typeof value==="boolean"||typeof value==="number"||typeof value==="string"){return true}if(Array.isArray(value)){return value.every(isJsonValue)}if(typeof value!=="object"||value===null){return false}const prototype=Object.getPrototypeOf(value);if(prototype!==Object.prototype&&prototype!==null){return false}return Object.values(value).every(isJsonValue)};var parseJsonValue=(value)=>{if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping","Value must be JSON-compatible")}return value};var encode=(prefix,value)=>`${prefix}.${Buffer.from(JSON.stringify(value)).toString("base64url")}`;var decode=(prefix,value)=>{if(!value.startsWith(`${prefix}.`)){throw new DataSourceMappingError("invalid_identity",`Expected an opaque ${prefix} identifier`)}try{const parsed=JSON.parse(Buffer.from(value.slice(prefix.length+1),"base64url").toString("utf-8"));if(!isJsonValue(parsed)){throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}return parsed}catch{throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}};var opaqueIdentity=(kind,fields,record)=>{const values=fields.map((field)=>{const value=record[field];if(typeof value!=="string"&&typeof value!=="number"){throw new DataSourceMappingError("invalid_identity",`Identity field ${field} must be a string or number`)}return value});return encode(`${kind}:id`,values)};var decodeIdentity=(kind,fields,id)=>{const values=decode(`${kind}:id`,id);if(!Array.isArray(values)||values.length!==fields.length){throw new DataSourceMappingError("invalid_identity","Opaque identifier does not match the configured identity")}return Object.fromEntries(fields.map((field,index)=>[field,values[index]]))};var opaqueRevision=(kind,revision)=>encode(`${kind}:rev`,revision);var optionalNativeString=(value)=>typeof value==="string"?value:undefined;var cursor=(kind,value)=>encode(`${kind}:cursor`,value);var decodeCursor=(kind,value)=>decode(`${kind}:cursor`,value);var projectedRelation=(kind,relation,value)=>{const normalize=(record)=>{if(typeof record!=="object"||record===null){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an object identity`)}const nativeRecord=Object.fromEntries(Object.entries(record));return opaqueIdentity(`${kind}:${relation.targetResourceId}`,relation.targetIdentityFields,nativeRecord)};if(relation.cardinality==="many"){if(!Array.isArray(value)){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an array`)}return value.map(normalize)}return value===null||value===undefined?null:normalize(value)};var project=(kind,projection,row)=>{const redacted=new Set(projection.redact);const relations=new Map((projection.relations??[]).map((relation)=>[relation.field,relation]));const entries=[];for(const field of projection.fields){if(redacted.has(field)){continue}const value=row[field];const relation=relations.get(field);if(relation!==undefined){entries.push([field,projectedRelation(kind,relation,value)]);continue}if(value===undefined){continue}if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping",`Field ${field} is not JSON-compatible`)}entries.push([field,value])}return Object.fromEntries(entries)};var record=(kind,options,row)=>{const deletedAt=options.softDelete?.deletedAt(row);const result={id:opaqueIdentity(kind,options.identity.fields,row),revision:opaqueRevision(kind,options.revision(row)),value:project(kind,options.projection,row)};if(deletedAt!==undefined){result.deletedAt=deletedAt}return result};var success=(correlationId,value)=>({correlationId,ok:true,value});var failure=(correlationId,error)=>({correlationId,error,ok:false});var nativeFilterOperator=(operator)=>operator.replaceAll(/_(?<letter>[a-z])/gu,(_match,letter)=>letter.toUpperCase());var unsupportedOperation=(correlationId,capabilities,operation)=>{const capability=resourceCapabilityByOperation[operation];if(capabilities[capability]===true){return}return failure(correlationId,{code:"capability_not_supported",details:{capability},message:`The data source does not support ${capability}`,retryable:false})};var conflict=(correlationId)=>failure(correlationId,{code:"conflict",message:"The expected revision does not match the current record",retryable:false});var invalid=(correlationId,cause)=>failure(correlationId,{code:"invalid_request",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The data-source request is invalid",retryable:false});var nativeFailure=(correlationId,cause)=>failure(correlationId,{code:"internal",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The native data source failed",retryable:false});var assertConfiguration=(options)=>{const fields=[...options.projection.fields,...options.projection.redact??[]];if(new Set(fields).size!==fields.length){throw new DataSourceMappingError("duplicate_field","Exposed and redacted fields must be disjoint and unique")}const maxPageSize=options.maxPageSize??100;if(!Number.isSafeInteger(maxPageSize)||maxPageSize<1){throw new DataSourceMappingError("invalid_pagination","maxPageSize must be a positive safe integer")}if(options.capabilities.pagination.length===0){throw new DataSourceMappingError("invalid_pagination","At least one pagination mode must be declared")}const declaredPagination=new Set(options.definition.query.pagination.modes);if(declaredPagination.size!==options.capabilities.pagination.length||options.capabilities.pagination.some((mode)=>!declaredPagination.has(mode))){throw new DataSourceMappingError("capability_mismatch","Data-source pagination must match the resource definition")}if(options.capabilities.relations!==(options.projection.relations?.length??0)>0){throw new DataSourceMappingError("capability_mismatch","Relation capability must match the explicit relation projection")}for(const capability of["create","hardDelete","restore","softDelete","update"]){if(options.capabilities[capability]!==(options.definition.capabilities[capability]===true)){throw new DataSourceMappingError("capability_mismatch",`${capability} capability must match the resource definition`)}}};var boundedLimit=(requested,maximum=100)=>{if(!Number.isSafeInteger(requested)||requested<1){throw new DataSourceMappingError("invalid_pagination","Page size must be a positive safe integer")}return Math.min(requested,maximum)};var expectedRevisionMatches=(kind,options,row,expectedRevision)=>opaqueRevision(kind,options.revision(row))===expectedRevision;var nativeFilter=(filter)=>{if("filters"in filter){return{...filter,filters:filter.filters.map(nativeFilter)}}if("filter"in filter){return{...filter,filter:nativeFilter(filter.filter)}}return{...filter,operator:nativeFilterOperator(filter.operator)}};var kind="strapi";var optionalProperty=(key,value)=>value===undefined?{}:{[key]:value};var documentId=(identity)=>{const value=identity.documentId;const documentIdentifier=optionalNativeString(value);if(documentIdentifier===undefined||documentIdentifier.length===0){throw new TypeError("Strapi identity must contain documentId")}return documentIdentifier};var localeFor=(options,identity)=>{if(options.localeField!==undefined&&identity!==undefined){const value=identity[options.localeField];const localeValue=optionalNativeString(value);if(localeValue!==undefined){return localeValue}}return options.locale};var validateStrapi=(options)=>{if(options.identity.fields[0]!=="documentId"){throw new TypeError("Strapi identity must prefer documentId")}if(!options.capabilities.nativePolicy){throw new TypeError("Strapi must declare nativePolicy support")}if(options.capabilities.transactions||options.capabilities.softDelete!==(options.softDelete!==undefined)){throw new TypeError("Strapi transaction and soft-delete capabilities require explicit policy")}if(options.capabilities.softDelete!==(options.plugin?.softDelete!==undefined)||options.capabilities.restore!==(options.plugin?.restore!==undefined)||options.capabilities.incrementalChanges!==(options.plugin?.changes!==undefined)){throw new TypeError("Strapi capabilities must match installed plugin hooks")}};var defineStrapiSource=(options)=>{assertConfiguration(options);validateStrapi(options);const maximum=options.maxPageSize??100;const documents=options.documents.documents(options.uid);const published=options.includeDrafts===true?"draft":"published";const sanitizedRecord=async(action,context,row)=>record(kind,options,await options.sanitize({action,context,value:row}));const paginationStart=(pagination)=>{if(pagination.mode==="cursor"){return pagination.cursor===undefined?0:decodeCursor(kind,pagination.cursor)}return(pagination.page-1)*pagination.pageSize};const executeList=async(request,context,publishedStatus)=>{await options.authorize({action:"find",context});const{pagination}=request.query;const limit=boundedLimit(pagination.mode==="cursor"?pagination.limit:pagination.pageSize,maximum);const start=paginationStart(pagination);const parameters={...optionalProperty("filters",request.query.filter===undefined?undefined:nativeFilter(request.query.filter)),limit,...optionalProperty("locale",options.locale),start,status:publishedStatus,...optionalProperty("sort",request.query.sort?.map(({direction,field})=>`${field}:${direction}`))};let rows;if(options.contentType==="single"){const single=await documents.findFirst(parameters);rows=single===null?[]:[single]}else{rows=await documents.findMany(parameters)}const items=await Promise.all(rows.map(async(row)=>await sanitizedRecord("find",context,row)));if(pagination.mode==="page"){const totalItems=options.contentType==="single"?items.length:await documents.count(parameters);return success(request.requestId,{items,page:pagination.page,pageSize:pagination.pageSize,pagination:"page",totalItems,totalPages:Math.ceil(totalItems/pagination.pageSize)})}return success(request.requestId,{items,...optionalProperty("nextCursor",items.length<limit?undefined:cursor(kind,start+items.length)),pagination:"cursor"})};const lifecycleMethod=(operation)=>operation==="restore"?options.plugin?.restore:options.plugin?.softDelete;const execute=async(request,context,requestOptions)=>{const unsupported=unsupportedOperation(request.requestId,options.definition.capabilities,request.operation);if(unsupported!==undefined){return unsupported}try{if(request.operation==="list"){return await executeList(request,context,published)}if(request.operation==="create"){await options.authorize({action:"create",context});const row2=await documents.create({data:parseJsonValue(request.value),...optionalProperty("locale",options.locale),status:published});return success(request.requestId,await sanitizedRecord("create",context,row2))}const identity=decodeIdentity(kind,options.identity.fields,request.id);const id=documentId(identity);const locale=localeFor(options,identity);await options.authorize({action:"find",context});const current=await documents.findOne({documentId:id,...optionalProperty("locale",locale),status:published});if(current===null){return{correlationId:request.requestId,error:{code:"not_found",message:"The Strapi document was not found",retryable:false},ok:false}}if(request.operation==="get"){return success(request.requestId,await sanitizedRecord("find",context,current))}if(!expectedRevisionMatches(kind,options,current,request.expectedRevision)){return conflict(request.requestId)}if(request.operation==="update"){await options.authorize({action:"update",context});const row2=await documents.update({data:parseJsonValue(request.value),documentId:id,...optionalProperty("locale",locale),status:published});return success(request.requestId,await sanitizedRecord("update",context,row2))}if(request.operation==="hard_delete"){await options.authorize({action:"delete",context});await documents.delete({documentId:id,...optionalProperty("locale",locale)});return success(request.requestId,null)}const action=request.operation==="restore"?"restore":"delete";await options.authorize({action,context});const method=lifecycleMethod(request.operation==="restore"?"restore":"soft_delete");const row=await method?.({documentId:id,...optionalProperty("locale",locale),organizationId:context.organizationId,...optionalProperty("signal",requestOptions?.signal),uid:options.uid});if(row===undefined){throw new TypeError(`${request.operation} is not supported`)}return success(request.requestId,await sanitizedRecord(action,context,row))}catch(error){return error instanceof TypeError?invalid(request.requestId,error):nativeFailure(request.requestId,error)}};const publication=(action)=>{const method=documents[action];return method===undefined?undefined:async(input)=>{await options.authorize({action:"publish",context:input.context});const row=await method({documentId:input.documentId,...optionalProperty("locale",input.locale)});const sanitized=await sanitizedRecord("publish",input.context,row);return sanitized.value}};const changes=options.plugin?.changes===undefined?undefined:async(request,context,requestOptions)=>{try{await options.authorize({action:"find",context});const after=request.cursor===undefined?undefined:decodeCursor(`${kind}:changes`,request.cursor);const page=await options.plugin?.changes?.({...optionalProperty("after",after),limit:boundedLimit(request.limit,maximum),...optionalProperty("locale",options.locale),organizationId:context.organizationId,overlapMs:options.incrementalChanges?.overlapMs??5000,...optionalProperty("signal",requestOptions?.signal),uid:options.uid});if(page===undefined){throw new TypeError("Changes are unavailable")}const projectedChanges=await Promise.all(page.changes.map(async(change)=>change.kind==="upsert"?{kind:"upsert",record:await sanitizedRecord("find",context,change.row)}:{deletedAt:change.deletedAt,id:opaqueIdentity(kind,options.identity.fields,change.identity),kind:"tombstone",revision:opaqueRevision(kind,change.revision)}));const final=page.changes.at(-1);const nextCursor=final===undefined?undefined:cursor(`${kind}:changes`,{externalId:final.kind==="upsert"?opaqueIdentity(kind,options.identity.fields,final.row):opaqueIdentity(kind,options.identity.fields,final.identity),updatedAt:final.kind==="upsert"?options.updatedAt(final.row):final.updatedAt});return success(request.requestId,{changes:projectedChanges,...optionalProperty("nextCursor",nextCursor)})}catch(error){return invalid(request.requestId,error)}};const publish=publication("publish");const unpublish=publication("unpublish");const source={authorization:options.authorization,...optionalProperty("changes",changes),dataSource:{capabilities:options.capabilities,kind},definition:options.definition,execute,publication:{...optionalProperty("publish",publish),...optionalProperty("unpublish",unpublish)}};return Object.freeze(source)};var defineStrapiGatewayPlugin=(hooks)=>Object.freeze(hooks);var{defineStrapiGatewayPlugin:defineStrapiGatewayPlugin2,defineStrapiSource:defineStrapiSource2}=exports_strapi;export{defineStrapiSource2 as defineStrapiSource,defineStrapiGatewayPlugin2 as defineStrapiGatewayPlugin};
|
|
1
|
+
var __defProp=Object.defineProperty;var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true,configurable:true,set:__exportSetter.bind(all,name)})};var exports_strapi={};__export(exports_strapi,{defineStrapiGatewayPlugin:()=>defineStrapiGatewayPlugin,defineStrapiSource:()=>defineStrapiSource});var resourceCapabilityByOperation={create:"create",get:"get",hard_delete:"hardDelete",list:"search",restore:"restore",soft_delete:"softDelete",update:"update"};class DataSourceMappingError extends TypeError{code;constructor(code,message){super(message);this.name="DataSourceMappingError";this.code=code}}var isJsonValue=(value)=>{if(value===null||typeof value==="boolean"||typeof value==="number"||typeof value==="string"){return true}if(Array.isArray(value)){return value.every(isJsonValue)}if(typeof value!=="object"||value===null){return false}const prototype=Object.getPrototypeOf(value);if(prototype!==Object.prototype&&prototype!==null){return false}return Object.values(value).every(isJsonValue)};var parseJsonValue=(value)=>{if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping","Value must be JSON-compatible")}return value};var encode=(prefix,value)=>`${prefix}.${Buffer.from(JSON.stringify(value)).toString("base64url")}`;var decode=(prefix,value)=>{if(!value.startsWith(`${prefix}.`)){throw new DataSourceMappingError("invalid_identity",`Expected an opaque ${prefix} identifier`)}try{const parsed=JSON.parse(Buffer.from(value.slice(prefix.length+1),"base64url").toString("utf-8"));if(!isJsonValue(parsed)){throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}return parsed}catch{throw new DataSourceMappingError("invalid_identity",`Invalid opaque ${prefix} identifier`)}};var opaqueIdentity=(kind,fields,record)=>{const values=fields.map((field)=>{const value=record[field];if(typeof value!=="string"&&typeof value!=="number"){throw new DataSourceMappingError("invalid_identity",`Identity field ${field} must be a string or number`)}return value});return encode(`${kind}:id`,values)};var decodeIdentity=(kind,fields,id)=>{const values=decode(`${kind}:id`,id);if(!Array.isArray(values)||values.length!==fields.length){throw new DataSourceMappingError("invalid_identity","Opaque identifier does not match the configured identity")}return Object.fromEntries(fields.map((field,index)=>[field,values[index]]))};var opaqueRevision=(kind,revision)=>encode(`${kind}:rev`,revision);var optionalNativeString=(value)=>typeof value==="string"?value:undefined;var cursor=(kind,value)=>encode(`${kind}:cursor`,value);var decodeCursor=(kind,value)=>decode(`${kind}:cursor`,value);var projectedRelation=(kind,relation,value)=>{const normalize=(record)=>{if(typeof record!=="object"||record===null){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an object identity`)}const nativeRecord=Object.fromEntries(Object.entries(record));return opaqueIdentity(`${kind}:${relation.targetResourceId}`,relation.targetIdentityFields,nativeRecord)};if(relation.cardinality==="many"){if(!Array.isArray(value)){throw new DataSourceMappingError("unsupported_mapping",`Relation ${relation.field} requires an array`)}return value.map(normalize)}return value===null||value===undefined?null:normalize(value)};var project=(kind,projection,row)=>{const redacted=new Set(projection.redact);const relations=new Map((projection.relations??[]).map((relation)=>[relation.field,relation]));const entries=[];for(const field of projection.fields){if(redacted.has(field)){continue}const value=row[field];const relation=relations.get(field);if(relation!==undefined){entries.push([field,projectedRelation(kind,relation,value)]);continue}if(value===undefined){continue}if(!isJsonValue(value)){throw new DataSourceMappingError("unsupported_mapping",`Field ${field} is not JSON-compatible`)}entries.push([field,value])}return Object.fromEntries(entries)};var record=(kind,options,row)=>{const deletedAt=options.softDelete?.deletedAt(row);const result={id:opaqueIdentity(kind,options.identity.fields,row),revision:opaqueRevision(kind,options.revision(row)),value:project(kind,options.projection,row)};if(deletedAt!==undefined){result.deletedAt=deletedAt}return result};var success=(correlationId,value)=>({correlationId,ok:true,value});var failure=(correlationId,error)=>({correlationId,error,ok:false});var nativeFilterOperator=(operator)=>operator.replaceAll(/_(?<letter>[a-z])/gu,(_match,letter)=>letter.toUpperCase());var unsupportedOperation=(correlationId,capabilities,operation)=>{const capability=resourceCapabilityByOperation[operation];if(capabilities[capability]===true){return}return failure(correlationId,{code:"capability_not_supported",details:{capability},message:`The data source does not support ${capability}`,retryable:false})};var conflict=(correlationId)=>failure(correlationId,{code:"conflict",message:"The expected revision does not match the current record",retryable:false});var invalid=(correlationId,cause)=>failure(correlationId,{code:"invalid_request",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The data-source request is invalid",retryable:false});var nativeFailure=(correlationId,cause)=>failure(correlationId,{code:"internal",details:{cause:cause instanceof Error?cause.message:String(cause)},message:"The native data source failed",retryable:false});var assertConfiguration=(options)=>{const fields=[...options.projection.fields,...options.projection.redact??[]];if(new Set(fields).size!==fields.length){throw new DataSourceMappingError("duplicate_field","Exposed and redacted fields must be disjoint and unique")}const maxPageSize=options.maxPageSize??100;if(!Number.isSafeInteger(maxPageSize)||maxPageSize<1){throw new DataSourceMappingError("invalid_pagination","maxPageSize must be a positive safe integer")}if(options.capabilities.pagination.length===0){throw new DataSourceMappingError("invalid_pagination","At least one pagination mode must be declared")}const declaredPagination=new Set(options.definition.query.pagination.modes);if(declaredPagination.size!==options.capabilities.pagination.length||options.capabilities.pagination.some((mode)=>!declaredPagination.has(mode))){throw new DataSourceMappingError("capability_mismatch","Data-source pagination must match the resource definition")}if(options.capabilities.relations!==(options.projection.relations?.length??0)>0){throw new DataSourceMappingError("capability_mismatch","Relation capability must match the explicit relation projection")}for(const capability of["create","hardDelete","restore","softDelete","update"]){if(options.capabilities[capability]!==(options.definition.capabilities[capability]===true)){throw new DataSourceMappingError("capability_mismatch",`${capability} capability must match the resource definition`)}}};var boundedLimit=(requested,maximum=100)=>{if(!Number.isSafeInteger(requested)||requested<1){throw new DataSourceMappingError("invalid_pagination","Page size must be a positive safe integer")}return Math.min(requested,maximum)};var expectedRevisionMatches=(kind,options,row,expectedRevision)=>opaqueRevision(kind,options.revision(row))===expectedRevision;var nativeFilter=(filter)=>{if("filters"in filter){return{...filter,filters:filter.filters.map(nativeFilter)}}if("filter"in filter){return{...filter,filter:nativeFilter(filter.filter)}}return{...filter,operator:nativeFilterOperator(filter.operator)}};var kind="strapi";var optionalProperty=(key,value)=>value===undefined?{}:{[key]:value};var documentId=(identity)=>{const value=identity.documentId;const documentIdentifier=optionalNativeString(value);if(documentIdentifier===undefined||documentIdentifier.length===0){throw new TypeError("Strapi identity must contain documentId")}return documentIdentifier};var localeFor=(options,identity)=>{if(options.localeField!==undefined&&identity!==undefined){const value=identity[options.localeField];const localeValue=optionalNativeString(value);if(localeValue!==undefined){return localeValue}}return options.locale};var validateStrapi=(options)=>{if(options.identity.fields[0]!=="documentId"){throw new TypeError("Strapi identity must prefer documentId")}if(!options.capabilities.nativePolicy){throw new TypeError("Strapi must declare nativePolicy support")}if(options.capabilities.transactions||options.capabilities.softDelete!==(options.softDelete!==undefined)){throw new TypeError("Strapi transaction and soft-delete capabilities require explicit policy")}if(options.capabilities.softDelete!==(options.plugin?.softDelete!==undefined)||options.capabilities.restore!==(options.plugin?.restore!==undefined)||options.capabilities.incrementalChanges!==(options.plugin?.changes!==undefined)){throw new TypeError("Strapi capabilities must match installed plugin hooks")}};var defineStrapiSource=(options)=>{assertConfiguration(options);validateStrapi(options);const maximum=options.maxPageSize??100;const documents=options.documents.documents(options.uid);const published=options.includeDrafts===true?"draft":"published";const sanitizedRecord=async(action,context,row)=>record(kind,options,await options.sanitize({action,context,value:row}));const paginationStart=(pagination)=>{if(pagination.mode==="cursor"){return pagination.cursor===undefined?0:decodeCursor(kind,pagination.cursor)}return(pagination.page-1)*pagination.pageSize};const executeList=async(request,context,publishedStatus)=>{await options.authorize({action:"find",context});const{pagination}=request.query;const limit=boundedLimit(pagination.mode==="cursor"?pagination.limit:pagination.pageSize,maximum);const start=paginationStart(pagination);const parameters={...optionalProperty("filters",request.query.filter===undefined?undefined:nativeFilter(request.query.filter)),limit,...optionalProperty("locale",options.locale),start,status:publishedStatus,...optionalProperty("sort",request.query.sort?.map(({direction,field})=>`${field}:${direction}`))};let rows;if(options.contentType==="single"){const single=await documents.findFirst(parameters);rows=single===null?[]:[single]}else{rows=await documents.findMany(parameters)}const items=await Promise.all(rows.map(async(row)=>await sanitizedRecord("find",context,row)));if(pagination.mode==="page"){const totalItems=options.contentType==="single"?items.length:await documents.count(parameters);return success(request.requestId,{items,page:pagination.page,pageSize:pagination.pageSize,pagination:"page",totalItems,totalPages:Math.ceil(totalItems/pagination.pageSize)})}return success(request.requestId,{items,...optionalProperty("nextCursor",items.length<limit?undefined:cursor(kind,start+items.length)),pagination:"cursor"})};const lifecycleMethod=(operation)=>operation==="restore"?options.plugin?.restore:options.plugin?.softDelete;const execute=async(request,context,requestOptions)=>{const unsupported=unsupportedOperation(request.requestId,options.definition.capabilities,request.operation);if(unsupported!==undefined){return unsupported}try{if(request.operation==="list"){return await executeList(request,context,published)}if(request.operation==="create"){await options.authorize({action:"create",context});const row=await documents.create({data:parseJsonValue(request.value),...optionalProperty("locale",options.locale),status:published});return success(request.requestId,await sanitizedRecord("create",context,row))}const identity=decodeIdentity(kind,options.identity.fields,request.id);const id=documentId(identity);const locale=localeFor(options,identity);await options.authorize({action:"find",context});const current=await documents.findOne({documentId:id,...optionalProperty("locale",locale),status:published});if(current===null){return{correlationId:request.requestId,error:{code:"not_found",message:"The Strapi document was not found",retryable:false},ok:false}}if(request.operation==="get"){return success(request.requestId,await sanitizedRecord("find",context,current))}if(!expectedRevisionMatches(kind,options,current,request.expectedRevision)){return conflict(request.requestId)}if(request.operation==="update"){await options.authorize({action:"update",context});const row=await documents.update({data:parseJsonValue(request.value),documentId:id,...optionalProperty("locale",locale),status:published});return success(request.requestId,await sanitizedRecord("update",context,row))}if(request.operation==="hard_delete"){await options.authorize({action:"delete",context});await documents.delete({documentId:id,...optionalProperty("locale",locale)});return success(request.requestId,null)}const action=request.operation==="restore"?"restore":"delete";await options.authorize({action,context});const method=lifecycleMethod(request.operation==="restore"?"restore":"soft_delete");const row=await method?.({documentId:id,...optionalProperty("locale",locale),organizationId:context.organizationId,...optionalProperty("signal",requestOptions?.signal),uid:options.uid});if(row===undefined){throw new TypeError(`${request.operation} is not supported`)}return success(request.requestId,await sanitizedRecord(action,context,row))}catch(error){return error instanceof TypeError?invalid(request.requestId,error):nativeFailure(request.requestId,error)}};const publication=(action)=>{const method=documents[action];return method===undefined?undefined:async(input)=>{await options.authorize({action:"publish",context:input.context});const row=await method({documentId:input.documentId,...optionalProperty("locale",input.locale)});const sanitized=await sanitizedRecord("publish",input.context,row);return sanitized.value}};const changes=options.plugin?.changes===undefined?undefined:async(request,context,requestOptions)=>{try{await options.authorize({action:"find",context});const after=request.cursor===undefined?undefined:decodeCursor(`${kind}:changes`,request.cursor);const page=await options.plugin?.changes?.({...optionalProperty("after",after),limit:boundedLimit(request.limit,maximum),...optionalProperty("locale",options.locale),organizationId:context.organizationId,overlapMs:options.incrementalChanges?.overlapMs??5000,...optionalProperty("signal",requestOptions?.signal),uid:options.uid});if(page===undefined){throw new TypeError("Changes are unavailable")}const projectedChanges=await Promise.all(page.changes.map(async(change)=>change.kind==="upsert"?{kind:"upsert",record:await sanitizedRecord("find",context,change.row)}:{deletedAt:change.deletedAt,id:opaqueIdentity(kind,options.identity.fields,change.identity),kind:"tombstone",revision:opaqueRevision(kind,change.revision)}));const final=page.changes.at(-1);const nextCursor=final===undefined?undefined:cursor(`${kind}:changes`,{externalId:final.kind==="upsert"?opaqueIdentity(kind,options.identity.fields,final.row):opaqueIdentity(kind,options.identity.fields,final.identity),updatedAt:final.kind==="upsert"?options.updatedAt(final.row):final.updatedAt});return success(request.requestId,{changes:projectedChanges,...optionalProperty("nextCursor",nextCursor)})}catch(error){return invalid(request.requestId,error)}};const publish=publication("publish");const unpublish=publication("unpublish");const source={authorization:options.authorization,...optionalProperty("changes",changes),dataSource:{capabilities:options.capabilities,kind},definition:options.definition,execute,publication:{...optionalProperty("publish",publish),...optionalProperty("unpublish",unpublish)}};return Object.freeze(source)};var defineStrapiGatewayPlugin=(hooks)=>Object.freeze(hooks);var{defineStrapiGatewayPlugin:defineStrapiGatewayPlugin2,defineStrapiSource:defineStrapiSource2}=exports_strapi;export{defineStrapiGatewayPlugin2 as defineStrapiGatewayPlugin,defineStrapiSource2 as defineStrapiSource};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true,configurable:true,set:__exportSetter.bind(all,name)})};var exports_drizzle_effect={};__export(exports_drizzle_effect,{
|
|
1
|
+
var __defProp=Object.defineProperty;var __returnValue=(v)=>v;function __exportSetter(name,newValue){this[name]=__returnValue.bind(null,newValue)}var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true,configurable:true,set:__exportSetter.bind(all,name)})};var exports_drizzle_effect={};__export(exports_drizzle_effect,{DrizzlePostgres:()=>DrizzlePostgres,DrizzlePostgresInitializationError:()=>DrizzlePostgresInitializationError,layerFromDatabase:()=>layerFromDatabase,layerNodePostgres:()=>layerNodePostgres});import{drizzle}from"drizzle-orm/node-postgres";import*as Context from"effect/Context";import*as Effect from"effect/Effect";import*as Layer from"effect/Layer";import{Pool}from"pg";import*as Schema from"effect/Schema";class DrizzlePostgresInitializationError extends Schema.TaggedError()("DrizzlePostgresInitializationError",{cause:Schema.Defect()}){}var makeDatabase=(pool)=>drizzle({client:pool});class DrizzlePostgres extends Context.Service()("@collective-intelligence/external-apps-server-sdk/DrizzlePostgres"){}var layerFromDatabase=(value)=>Layer.succeed(DrizzlePostgres,value);var layerNodePostgres=(options)=>Layer.effect(DrizzlePostgres,Effect.acquireRelease(Effect.sync(()=>new Pool(options.connection)),(pool)=>Effect.promise(async()=>{await pool.end()})).pipe(Effect.flatMap((pool)=>{const value=DrizzlePostgres.of({database:makeDatabase(pool),pool});const{migrate}=options;return migrate===undefined?Effect.succeed(value):Effect.tryPromise({catch:(cause)=>new DrizzlePostgresInitializationError({cause}),try:migrate.bind(undefined,value)}).pipe(Effect.as(value))})));var{DrizzlePostgres:DrizzlePostgres2,DrizzlePostgresInitializationError:DrizzlePostgresInitializationError2,layerFromDatabase:layerFromDatabase2,layerNodePostgres:layerNodePostgres2}=exports_drizzle_effect;export{DrizzlePostgres2 as DrizzlePostgres,DrizzlePostgresInitializationError2 as DrizzlePostgresInitializationError,layerFromDatabase2 as layerFromDatabase,layerNodePostgres2 as layerNodePostgres};
|