@igorchugurov/public-api-sdk 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -32,7 +32,8 @@ var __export = (target, all) => {
32
32
  var slug_exports = {};
33
33
  __export(slug_exports, {
34
34
  generateSlug: () => generateSlug,
35
- generateUniqueSlugForInstance: () => generateUniqueSlugForInstance
35
+ generateUniqueSlugForInstance: () => generateUniqueSlugForInstance,
36
+ validateSlug: () => validateSlug
36
37
  });
37
38
  function generateSlug(name) {
38
39
  if (!name || typeof name !== "string") {
@@ -40,6 +41,16 @@ function generateSlug(name) {
40
41
  }
41
42
  return name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").substring(0, 100);
42
43
  }
44
+ function validateSlug(slug) {
45
+ if (!slug || typeof slug !== "string") {
46
+ return false;
47
+ }
48
+ if (slug.length === 0 || slug.length > 100) {
49
+ return false;
50
+ }
51
+ const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
52
+ return slugRegex.test(slug);
53
+ }
43
54
  function generateRandomSuffix() {
44
55
  return Math.random().toString(36).substring(2, 6);
45
56
  }
@@ -754,6 +765,7 @@ function flattenInstance(instance, fields, relationsAsIds = false) {
754
765
  }
755
766
 
756
767
  // src/client.ts
768
+ init_slug();
757
769
  var _PublicAPIClient = class _PublicAPIClient extends BasePublicAPIClient {
758
770
  constructor(supabase, projectId, mode, options = {}) {
759
771
  super(supabase, projectId, options);
@@ -905,6 +917,134 @@ var _PublicAPIClient = class _PublicAPIClient extends BasePublicAPIClient {
905
917
  handleSupabaseError(error);
906
918
  }
907
919
  }
920
+ /**
921
+ * Получить один экземпляр по slug
922
+ */
923
+ async getInstanceBySlug(entityDefinitionId, slug, params) {
924
+ var _a;
925
+ try {
926
+ if (!validateSlug(slug)) {
927
+ throw new ValidationError(
928
+ "slug",
929
+ "Slug must contain only lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen"
930
+ );
931
+ }
932
+ const fields = await this.getFields(entityDefinitionId);
933
+ const { data: instance, error: instanceError } = await this.supabase.from("entity_instance").select("*").eq("slug", slug).eq("entity_definition_id", entityDefinitionId).eq("project_id", this.projectId).single();
934
+ if (instanceError || !instance) {
935
+ handleInstanceError(
936
+ instanceError || new Error("Instance not found"),
937
+ slug
938
+ );
939
+ }
940
+ const transformedInstance = transformEntityInstance(instance);
941
+ if (transformedInstance.entityDefinitionId !== entityDefinitionId) {
942
+ throw new NotFoundError("Entity instance", slug);
943
+ }
944
+ const relationFields = fields.filter(
945
+ (f) => f.dbType === "manyToMany" || f.dbType === "manyToOne" || f.dbType === "oneToMany" || f.dbType === "oneToOne"
946
+ );
947
+ const relations = {};
948
+ if (relationFields.length > 0) {
949
+ const relationFieldIds = relationFields.map((f) => f.id).filter((id) => Boolean(id));
950
+ if (relationFieldIds.length > 0) {
951
+ const { data: allRelations, error: relationsError } = await this.supabase.from("entity_relation").select("target_instance_id, relation_field_id").eq("source_instance_id", transformedInstance.id).in("relation_field_id", relationFieldIds);
952
+ if (relationsError) {
953
+ throw new SDKError(
954
+ "RELATIONS_LOAD_ERROR",
955
+ `Failed to load relations for instance with slug ${slug}: ${relationsError.message}`,
956
+ 500,
957
+ relationsError
958
+ );
959
+ }
960
+ if (allRelations && allRelations.length > 0) {
961
+ const targetInstanceIds = [
962
+ ...new Set(allRelations.map((r) => r.target_instance_id))
963
+ ];
964
+ const { data: relatedInstances, error: instancesError } = await this.supabase.from("entity_instance").select("*").in("id", targetInstanceIds);
965
+ if (instancesError) {
966
+ throw new SDKError(
967
+ "RELATED_INSTANCES_LOAD_ERROR",
968
+ `Failed to load related instances for instance with slug ${slug}: ${instancesError.message}`,
969
+ 500,
970
+ instancesError
971
+ );
972
+ }
973
+ if (relatedInstances) {
974
+ const relatedInstancesMap = new Map(
975
+ relatedInstances.map((inst) => [
976
+ inst.id,
977
+ transformEntityInstance(inst)
978
+ ])
979
+ );
980
+ for (const relation of allRelations) {
981
+ const relationField = relationFields.find(
982
+ (f) => f.id === relation.relation_field_id
983
+ );
984
+ if (relationField) {
985
+ const relatedInstance = relatedInstancesMap.get(
986
+ relation.target_instance_id
987
+ );
988
+ if (relatedInstance) {
989
+ if (!relations[relationField.name]) {
990
+ relations[relationField.name] = [];
991
+ }
992
+ relations[relationField.name].push(
993
+ relatedInstance
994
+ );
995
+ }
996
+ }
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+ const fileFields = fields.filter(
1003
+ (f) => f.type === "files" || f.type === "images"
1004
+ );
1005
+ if (fileFields.length > 0) {
1006
+ const { data: allFiles, error: filesError } = await this.supabase.from("entity_file").select("id, field_id").eq("entity_instance_id", transformedInstance.id);
1007
+ if (filesError) {
1008
+ throw new SDKError(
1009
+ "FILES_LOAD_ERROR",
1010
+ `Failed to load files for instance with slug ${slug}: ${filesError.message}`,
1011
+ 500,
1012
+ filesError
1013
+ );
1014
+ }
1015
+ if (allFiles) {
1016
+ const filesByFieldId = /* @__PURE__ */ new Map();
1017
+ allFiles.forEach((file) => {
1018
+ if (file.field_id) {
1019
+ if (!filesByFieldId.has(file.field_id)) {
1020
+ filesByFieldId.set(file.field_id, []);
1021
+ }
1022
+ filesByFieldId.get(file.field_id).push(file.id);
1023
+ }
1024
+ });
1025
+ fileFields.forEach((field) => {
1026
+ const fileIds = filesByFieldId.get(field.id) || [];
1027
+ if (fileIds.length > 0 || !transformedInstance.data[field.name]) {
1028
+ transformedInstance.data[field.name] = fileIds;
1029
+ }
1030
+ });
1031
+ }
1032
+ }
1033
+ const instanceWithRelations = __spreadProps(__spreadValues({}, transformedInstance), {
1034
+ relations: Object.keys(relations).length > 0 ? relations : void 0
1035
+ });
1036
+ return flattenInstance(
1037
+ instanceWithRelations,
1038
+ fields.map((f) => ({ name: f.name, dbType: f.dbType })),
1039
+ (_a = params == null ? void 0 : params.relationsAsIds) != null ? _a : false
1040
+ );
1041
+ } catch (error) {
1042
+ if (error instanceof NotFoundError || error instanceof PermissionDeniedError || error instanceof ValidationError || error instanceof SDKError) {
1043
+ throw error;
1044
+ }
1045
+ handleSupabaseError(error);
1046
+ }
1047
+ }
908
1048
  /**
909
1049
  * Получить список экземпляров
910
1050
  * Поддерживает поиск, фильтры (JSONB и relation), пагинацию