@carthooks/arcubase-cli 0.1.25 → 0.1.26

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.
@@ -16529,10 +16529,10 @@ var PermitFieldPermitSchema = external_exports.lazy(() => external_exports.objec
16529
16529
  var PermitPolicySchema = external_exports.lazy(() => external_exports.object({ "actions": external_exports.array(external_exports.string()).optional(), "all_fields_read": external_exports.boolean().optional(), "all_fields_write": external_exports.boolean().optional(), "condition": PermitConditionSetSchema.optional(), "description": external_exports.string().optional(), "fields": external_exports.array(PermitFieldPermitSchema).optional(), "id": external_exports.string().optional(), "key": external_exports.string().optional(), "name": external_exports.string().optional() }).strict());
16530
16530
  var PermitUserScopeSchema = external_exports.lazy(() => external_exports.object({ "data": external_exports.object({ "name": external_exports.string().optional() }).strict().optional(), "id": external_exports.number().optional(), "type": external_exports.string().optional() }).strict());
16531
16531
  var EntityIngressOptionsSchema = external_exports.lazy(() => external_exports.object({ "i18n_name": I18NTextSchema.optional(), "list_options": PermitEntityListOptionsSchema.optional(), "policy": PermitPolicySchema.optional(), "user_scope": external_exports.array(PermitUserScopeSchema).optional() }).strict());
16532
- var AppIngressBulkApplyItemVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "rule_id": external_exports.number().optional(), "table_id": external_exports.number().optional(), "type": external_exports.string().optional() }).strict());
16532
+ var AppIngressBulkApplyItemVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "key": external_exports.string().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "rule_id": external_exports.number().optional(), "table_id": external_exports.number().optional(), "type": external_exports.string().optional() }).strict());
16533
16533
  var AppIngressBulkApplyReqVOSchema = external_exports.lazy(() => external_exports.object({ "dry_run": external_exports.boolean().optional(), "items": external_exports.array(AppIngressBulkApplyItemVOSchema).optional(), "mode": external_exports.string().optional() }).strict());
16534
- var AppIngressCreateReqVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "entity_id": external_exports.number().optional(), "icon_name": external_exports.string().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "type": external_exports.string().optional(), "url": external_exports.string().optional() }).strict());
16535
- var AppIngressUpdateReqVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "update": external_exports.array(external_exports.string()).optional() }).strict());
16534
+ var AppIngressCreateReqVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "entity_id": external_exports.number().optional(), "icon_name": external_exports.string().optional(), "key": external_exports.string().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "type": external_exports.string().optional(), "url": external_exports.string().optional() }).strict());
16535
+ var AppIngressUpdateReqVOSchema = external_exports.lazy(() => external_exports.object({ "enabled": external_exports.boolean().optional(), "key": external_exports.string().optional(), "name": external_exports.string().optional(), "options": EntityIngressOptionsSchema.optional(), "update": external_exports.array(external_exports.string()).optional() }).strict());
16536
16536
  var WidgetsTypeCodeSchema = external_exports.lazy(() => external_exports.union([external_exports.literal(1), external_exports.literal(2)]));
16537
16537
  var WidgetsTypeSchema = external_exports.lazy(() => external_exports.object({ "dashboard_id": external_exports.number().optional(), "ingress_id": external_exports.number().optional(), "type": WidgetsTypeCodeSchema.optional() }).strict());
16538
16538
  var AppNewWidgetsReqVOSchema = external_exports.lazy(() => external_exports.object({ "options": WidgetsTypeSchema.optional(), "type": external_exports.string().optional() }).strict());
@@ -18689,15 +18689,8 @@ function renderCommandHelpExamples(scope, command) {
18689
18689
  ].join("\n").trimEnd();
18690
18690
  }
18691
18691
 
18692
- // node_modules/@arcubase/code-gen/dist/index.js
18693
- var ArcubaseCodeGenError = class extends Error {
18694
- code;
18695
- constructor(code, message) {
18696
- super(message);
18697
- this.code = code;
18698
- this.name = "ArcubaseCodeGenError";
18699
- }
18700
- };
18692
+ // src/runtime/dev_sdk_gen.ts
18693
+ var identifierPattern = /^[A-Za-z][A-Za-z0-9_]*$/;
18701
18694
  function isRecord3(value) {
18702
18695
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
18703
18696
  }
@@ -18706,18 +18699,9 @@ function unwrapData(payload) {
18706
18699
  }
18707
18700
  function toPascalCase(value) {
18708
18701
  const words = value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter(Boolean);
18709
- if (words.length === 0)
18710
- return "Entity";
18702
+ if (words.length === 0) return "Ingress";
18711
18703
  return words.map((word) => `${word[0].toUpperCase()}${word.slice(1)}`).join("");
18712
18704
  }
18713
- function toCamelCase(value) {
18714
- const pascal = toPascalCase(value);
18715
- return `${pascal[0].toLowerCase()}${pascal.slice(1)}`;
18716
- }
18717
- function sanitizeEntityKey(entity) {
18718
- const fallback = entity.sdkName || `entity_${entity.id}`;
18719
- return toCamelCase(fallback) === "entity" ? `entity${entity.id}` : toCamelCase(fallback);
18720
- }
18721
18705
  function normalizeFieldType(type) {
18722
18706
  switch (type) {
18723
18707
  case "number":
@@ -18744,65 +18728,122 @@ function normalizeFieldType(type) {
18744
18728
  return "string";
18745
18729
  }
18746
18730
  }
18747
- function normalizeEntities(payload) {
18731
+ function normalizeField(field) {
18732
+ if (typeof field.id !== "number" || typeof field.label !== "string" || typeof field.type !== "string") {
18733
+ return void 0;
18734
+ }
18735
+ const children = Array.isArray(field.children) ? field.children.filter((child) => isRecord3(child)).map(normalizeField).filter((child) => Boolean(child)) : void 0;
18736
+ return {
18737
+ id: field.id,
18738
+ label: field.label,
18739
+ key: typeof field.key === "string" ? field.key.trim() : "",
18740
+ type: field.type,
18741
+ required: field.required === true,
18742
+ options: isRecord3(field.options) ? field.options : void 0,
18743
+ children
18744
+ };
18745
+ }
18746
+ function normalizeEntity(payload, appId) {
18747
+ if (!isRecord3(payload) || typeof payload.id !== "number" || typeof payload.name !== "string") {
18748
+ throw new CLIError("SDK_GEN_INVALID_SCHEMA", "sdk-gen expected ingress.entity with id and name", 2);
18749
+ }
18750
+ const fields = Array.isArray(payload.fields) ? payload.fields.filter((field) => isRecord3(field)).map(normalizeField).filter((field) => Boolean(field)) : [];
18751
+ return {
18752
+ appId,
18753
+ id: payload.id,
18754
+ name: payload.name,
18755
+ fields
18756
+ };
18757
+ }
18758
+ function normalizeActions(ingress) {
18759
+ const policy = isRecord3(ingress.policy) ? ingress.policy : isRecord3(ingress.options) && isRecord3(ingress.options.policy) ? ingress.options.policy : void 0;
18760
+ const source = Array.isArray(ingress.actions) ? ingress.actions : Array.isArray(policy?.actions) ? policy.actions : [];
18761
+ return source.filter((action) => typeof action === "string" && action.trim() !== "").map((action) => action.trim());
18762
+ }
18763
+ function normalizeIngresses(payload) {
18748
18764
  const root = unwrapData(payload);
18749
18765
  if (!isRecord3(root)) {
18750
- throw new ArcubaseCodeGenError("SDK_GEN_INVALID_SCHEMA", "sdk-gen expected an app detail object");
18766
+ throw new CLIError("SDK_GEN_INVALID_SCHEMA", "sdk-gen expected an app ingress schema object", 2);
18751
18767
  }
18752
18768
  const appId = typeof root.id === "number" ? root.id : typeof root.app_id === "number" ? root.app_id : void 0;
18753
18769
  if (!appId) {
18754
- throw new ArcubaseCodeGenError("SDK_GEN_APP_ID_REQUIRED", "sdk-gen expected app id in app detail response");
18770
+ throw new CLIError("SDK_GEN_APP_ID_REQUIRED", "sdk-gen expected app id in schema payload", 2);
18755
18771
  }
18756
- const sourceEntities = Array.isArray(root.entities) ? root.entities : Array.isArray(root.tables) ? root.tables : Array.isArray(root.entitys) ? root.entitys : [];
18757
- const entities = sourceEntities.filter((item) => isRecord3(item)).filter((item) => typeof item.id === "number" && typeof item.name === "string").map((item) => {
18758
- const fields = Array.isArray(item.fields) ? item.fields.filter((field) => isRecord3(field)).filter((field) => typeof field.id === "number" && typeof field.label === "string" && typeof field.type === "string").map((field) => ({
18759
- id: field.id,
18760
- label: field.label,
18761
- key: typeof field.key === "string" ? field.key.trim() : "",
18762
- type: field.type,
18763
- required: field.required === true,
18764
- options: isRecord3(field.options) ? field.options : void 0
18765
- })) : [];
18766
- const entity = {
18772
+ const sourceIngresses = Array.isArray(root.ingresses) ? root.ingresses : [];
18773
+ if (sourceIngresses.length === 0) {
18774
+ throw new CLIError("SDK_GEN_NO_INGRESSES", "sdk-gen could not find ingresses in schema payload", 2);
18775
+ }
18776
+ const ingresses = sourceIngresses.filter((item) => isRecord3(item)).map((item) => {
18777
+ const entity = normalizeEntity(item.entity, appId);
18778
+ const options = isRecord3(item.options) ? item.options : {};
18779
+ const hashId = typeof item.hash_id === "string" ? item.hash_id.trim() : typeof item.hashId === "string" ? item.hashId.trim() : "";
18780
+ return {
18767
18781
  appId,
18768
- id: item.id,
18769
- name: item.name,
18770
- sdkName: typeof item.key === "string" && item.key.trim() ? item.key.trim() : "",
18771
- fields
18782
+ id: typeof item.id === "number" ? item.id : void 0,
18783
+ hashId,
18784
+ key: typeof item.key === "string" ? item.key.trim() : "",
18785
+ name: typeof item.name === "string" && item.name.trim() ? item.name.trim() : String(item.key ?? ""),
18786
+ actions: normalizeActions(item),
18787
+ entity,
18788
+ listOptions: isRecord3(options.list_options) ? options.list_options : isRecord3(item.list_options) ? item.list_options : void 0
18772
18789
  };
18773
- entity.sdkName = sanitizeEntityKey(entity);
18774
- return entity;
18775
18790
  });
18776
- if (entities.length === 0) {
18777
- throw new ArcubaseCodeGenError("SDK_GEN_NO_ENTITIES", "sdk-gen could not find entities in app detail response");
18791
+ validateIngresses(ingresses);
18792
+ return ingresses;
18793
+ }
18794
+ function walkFields(fields, visit) {
18795
+ for (const field of fields) {
18796
+ visit(field);
18797
+ if (field.children && field.children.length > 0) {
18798
+ walkFields(field.children, visit);
18799
+ }
18778
18800
  }
18779
- validateEntities(entities);
18780
- return entities;
18781
18801
  }
18782
- function validateEntities(entities) {
18783
- const entityKeys = /* @__PURE__ */ new Set();
18784
- for (const entity of entities) {
18785
- if (entityKeys.has(entity.sdkName)) {
18786
- throw new ArcubaseCodeGenError("SDK_GEN_DUPLICATE_ENTITY_KEY", `duplicate generated entity key: ${entity.sdkName}`);
18802
+ function allFields(entity) {
18803
+ const out = [];
18804
+ walkFields(entity.fields, (field) => out.push(field));
18805
+ return out;
18806
+ }
18807
+ function validateIngresses(ingresses) {
18808
+ const ingressKeys = /* @__PURE__ */ new Set();
18809
+ for (const ingress of ingresses) {
18810
+ if (!ingress.key) {
18811
+ throw new CLIError("SDK_GEN_INGRESS_KEY_REQUIRED", `ingress.key is required for ${ingress.name || "unnamed ingress"}`, 2);
18812
+ }
18813
+ if (!identifierPattern.test(ingress.key)) {
18814
+ throw new CLIError("SDK_GEN_INVALID_INGRESS_KEY", `ingress.key must be a TypeScript identifier: ${ingress.key}`, 2);
18815
+ }
18816
+ if (ingressKeys.has(ingress.key)) {
18817
+ throw new CLIError("SDK_GEN_DUPLICATE_INGRESS_KEY", `duplicate ingress.key: ${ingress.key}`, 2);
18818
+ }
18819
+ ingressKeys.add(ingress.key);
18820
+ if (!ingress.hashId) {
18821
+ throw new CLIError("SDK_GEN_INGRESS_HASH_ID_REQUIRED", `ingress.hash_id is required for ${ingress.key}`, 2);
18787
18822
  }
18788
- entityKeys.add(entity.sdkName);
18789
18823
  const fieldKeys = /* @__PURE__ */ new Set();
18790
- for (const field of entity.fields) {
18824
+ for (const field of allFields(ingress.entity)) {
18791
18825
  if (!field.key) {
18792
- throw new ArcubaseCodeGenError("SDK_GEN_FIELD_KEY_REQUIRED", `field.key is required for ${entity.name}.${field.label} (${field.id})`);
18826
+ throw new CLIError("SDK_GEN_FIELD_KEY_REQUIRED", `field.key is required for ${ingress.entity.name}.${field.label} (${field.id})`, 2);
18793
18827
  }
18794
- if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(field.key)) {
18795
- throw new ArcubaseCodeGenError("SDK_GEN_INVALID_FIELD_KEY", `field.key must be a TypeScript identifier: ${entity.name}.${field.key}`);
18828
+ if (!identifierPattern.test(field.key)) {
18829
+ throw new CLIError("SDK_GEN_INVALID_FIELD_KEY", `field.key must be a TypeScript identifier: ${ingress.entity.name}.${field.key}`, 2);
18796
18830
  }
18797
18831
  if (fieldKeys.has(field.key)) {
18798
- throw new ArcubaseCodeGenError("SDK_GEN_DUPLICATE_FIELD_KEY", `duplicate field.key in ${entity.name}: ${field.key}`);
18832
+ throw new CLIError("SDK_GEN_DUPLICATE_FIELD_KEY", `duplicate field.key in ${ingress.entity.name}: ${field.key}`, 2);
18799
18833
  }
18800
18834
  fieldKeys.add(field.key);
18801
18835
  }
18802
18836
  }
18803
18837
  }
18838
+ function hasAction(ingress, action) {
18839
+ return ingress.actions.includes(action);
18840
+ }
18841
+ function methodLines(lines) {
18842
+ return lines.length > 0 ? `${lines.join("\n\n")}
18843
+ ` : "";
18844
+ }
18804
18845
  function emitRuntime() {
18805
- return `export type ArcubaseSdkConfig = {
18846
+ return `export type ArcubaseClientConfig = {
18806
18847
  baseURL: string
18807
18848
  accessToken?: string
18808
18849
  refreshToken?: string
@@ -18816,7 +18857,6 @@ export type ArcubaseRow<TFields> = {
18816
18857
  }
18817
18858
 
18818
18859
  export type ArcubaseRuntime = {
18819
- config: ArcubaseSdkConfig
18820
18860
  request<T>(method: string, endpoint: string, body?: unknown): Promise<T>
18821
18861
  }
18822
18862
 
@@ -18825,7 +18865,7 @@ type ArcubaseEnvelope<T> = {
18825
18865
  error?: { message?: string; key?: string; type?: string }
18826
18866
  }
18827
18867
 
18828
- export function createRuntime(config: ArcubaseSdkConfig): ArcubaseRuntime {
18868
+ export function createRuntime(config: ArcubaseClientConfig): ArcubaseRuntime {
18829
18869
  let accessToken = config.accessToken ?? ''
18830
18870
  let refreshToken = config.refreshToken ?? ''
18831
18871
 
@@ -18836,6 +18876,7 @@ export function createRuntime(config: ArcubaseSdkConfig): ArcubaseRuntime {
18836
18876
  headers: {
18837
18877
  'Content-Type': 'application/json',
18838
18878
  ...(accessToken ? { Authorization: \`Bearer \${accessToken}\` } : {}),
18879
+ ...(refreshToken ? { 'X-Arcubase-Refresh-Token': refreshToken } : {}),
18839
18880
  },
18840
18881
  body: body === undefined ? undefined : JSON.stringify(body),
18841
18882
  })
@@ -18846,21 +18887,72 @@ export function createRuntime(config: ArcubaseSdkConfig): ArcubaseRuntime {
18846
18887
  return payload?.data as T
18847
18888
  }
18848
18889
 
18849
- return {
18850
- config: { ...config, accessToken, refreshToken },
18851
- request,
18890
+ return { request }
18891
+ }
18892
+
18893
+ export function toArcubaseFields<T extends Record<string, any>>(fields: Partial<T>, fieldIds: Record<string, number>): Record<string, any> {
18894
+ const out: Record<string, any> = {}
18895
+ for (const [key, value] of Object.entries(fields)) {
18896
+ if (value === undefined) continue
18897
+ const fieldId = fieldIds[key]
18898
+ if (!fieldId) {
18899
+ throw new Error(\`Unknown Arcubase field: \${key}\`)
18900
+ }
18901
+ out[String(fieldId)] = value
18902
+ }
18903
+ return out
18904
+ }
18905
+
18906
+ export function fromArcubaseFields<T>(raw: Record<string, any> | undefined, fieldIds: Record<string, number>): T {
18907
+ const out: Record<string, any> = {}
18908
+ const source = raw ?? {}
18909
+ for (const [key, fieldId] of Object.entries(fieldIds)) {
18910
+ if (String(fieldId) in source) {
18911
+ out[key] = source[String(fieldId)]
18912
+ }
18852
18913
  }
18914
+ return out as T
18915
+ }
18916
+
18917
+ export function toArcubaseColumn(column: string, fieldIds: Record<string, number>): string {
18918
+ return fieldIds[column] ? \`:\${fieldIds[column]}\` : column
18919
+ }
18920
+
18921
+ export function mapArcubaseCondition(value: unknown, fieldIds: Record<string, number>): unknown {
18922
+ if (Array.isArray(value)) {
18923
+ return value.map((item) => mapArcubaseCondition(item, fieldIds))
18924
+ }
18925
+ if (!value || typeof value !== 'object') {
18926
+ return value
18927
+ }
18928
+ const out: Record<string, unknown> = {}
18929
+ for (const [key, child] of Object.entries(value as Record<string, unknown>)) {
18930
+ if (key === 'column' && typeof child === 'string') {
18931
+ out[key] = toArcubaseColumn(child, fieldIds)
18932
+ } else {
18933
+ const mappedKey = fieldIds[key] ? \`:\${fieldIds[key]}\` : key
18934
+ out[mappedKey] = mapArcubaseCondition(child, fieldIds)
18935
+ }
18936
+ }
18937
+ return out
18938
+ }
18939
+
18940
+ export function mapArcubaseSorts<T extends { column: string; order?: string }>(sorts: T[] | undefined, fieldIds: Record<string, number>): T[] | undefined {
18941
+ return sorts?.map((sort) => ({ ...sort, column: toArcubaseColumn(sort.column, fieldIds) }))
18853
18942
  }
18854
18943
  `;
18855
18944
  }
18856
- function emitSchema(entities) {
18945
+ function emitSchema(ingresses) {
18857
18946
  const schema = {
18858
- entities: Object.fromEntries(entities.map((entity) => [
18859
- entity.sdkName,
18947
+ ingresses: Object.fromEntries(ingresses.map((ingress) => [
18948
+ ingress.key,
18860
18949
  {
18861
- entityId: entity.id,
18862
- name: entity.name,
18863
- fields: Object.fromEntries(entity.fields.map((field) => [
18950
+ appId: ingress.appId,
18951
+ ingressId: ingress.hashId,
18952
+ entityId: ingress.entity.id,
18953
+ name: ingress.name,
18954
+ actions: ingress.actions,
18955
+ fields: Object.fromEntries(allFields(ingress.entity).map((field) => [
18864
18956
  field.key,
18865
18957
  {
18866
18958
  fieldId: field.id,
@@ -18874,17 +18966,177 @@ function emitSchema(entities) {
18874
18966
  };
18875
18967
  return `export const arcubaseSchema = ${JSON.stringify(schema, null, 2)} as const
18876
18968
 
18877
- export type ArcubaseEntityKey = keyof typeof arcubaseSchema.entities
18969
+ export type ArcubaseIngressKey = keyof typeof arcubaseSchema.ingresses
18878
18970
  `;
18879
18971
  }
18880
- function emitEntity(entity) {
18881
- const typeName = toPascalCase(entity.sdkName);
18882
- const fieldLines = entity.fields.map((field) => {
18972
+ function emitIngress(ingress) {
18973
+ const typeName = toPascalCase(ingress.key);
18974
+ const fields = allFields(ingress.entity);
18975
+ const fieldLines = fields.map((field) => {
18883
18976
  const optional2 = field.required ? "" : "?";
18884
18977
  return ` ${field.key}${optional2}: ${normalizeFieldType(field.type)}`;
18885
18978
  });
18886
- const fieldMapLines = entity.fields.map((field) => ` ${field.key}: ${field.id},`);
18887
- return `import type { ArcubaseRuntime, ArcubaseRow } from '../runtime.js'
18979
+ const fieldMapLines = fields.map((field) => ` ${field.key}: ${field.id},`);
18980
+ const methodChunks = [];
18981
+ if (hasAction(ingress, "view")) {
18982
+ methodChunks.push(` async query(params: ${typeName}QueryParams = {}): Promise<{ items: ArcubaseRow<${typeName}Fields>[]; total?: number; offset?: number; limit?: number }> {
18983
+ const data = await runtime.request<{ items?: Record<string, any>[]; total?: number; offset?: number; limit?: number }>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/data-query\`, {
18984
+ ...params,
18985
+ policy_id: ingressId,
18986
+ search: mapArcubaseCondition(params.search, fieldIds),
18987
+ sorts: mapArcubaseSorts(params.sorts, fieldIds),
18988
+ })
18989
+ return {
18990
+ items: (data.items ?? []).map(mapRow),
18991
+ total: data.total,
18992
+ offset: data.offset,
18993
+ limit: data.limit,
18994
+ }
18995
+ },
18996
+
18997
+ async get(rowId: string | number): Promise<ArcubaseRow<${typeName}Fields>> {
18998
+ const data = await runtime.request<{ record?: Record<string, any> }>('GET', \`/entity/${ingress.appId}/${ingress.entity.id}/row/\${rowId}?policy_id=\${encodeURIComponent(ingressId)}\`)
18999
+ return mapRow(data.record ?? {})
19000
+ },`);
19001
+ }
19002
+ if (hasAction(ingress, "add")) {
19003
+ methodChunks.push(` async prepareCreate(): Promise<Record<string, any>> {
19004
+ return runtime.request<Record<string, any>>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/prepare\`, {
19005
+ policy_id: ingressId,
19006
+ })
19007
+ },
19008
+
19009
+ async create(fields: ${typeName}CreateInput): Promise<number> {
19010
+ return runtime.request<number>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/insert\`, {
19011
+ fields: toArcubaseFields(fields, fieldIds),
19012
+ policy_id: ingressId,
19013
+ })
19014
+ },`);
19015
+ }
19016
+ if (hasAction(ingress, "edit")) {
19017
+ methodChunks.push(` async update(rowId: string | number, fields: ${typeName}UpdateInput): Promise<boolean> {
19018
+ const data = toArcubaseFields(fields, fieldIds)
19019
+ return runtime.request<boolean>('PUT', \`/entity/${ingress.appId}/${ingress.entity.id}/row/\${rowId}\`, {
19020
+ data,
19021
+ changed_fields: Object.keys(data).map((fieldId) => Number(fieldId)),
19022
+ policy_id: ingressId,
19023
+ })
19024
+ },`);
19025
+ }
19026
+ if (hasAction(ingress, "delete")) {
19027
+ methodChunks.push(` async delete(selection: ${typeName}Selection): Promise<{ deleted?: number } | boolean> {
19028
+ return runtime.request<{ deleted?: number } | boolean>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/delete-item\`, {
19029
+ policy_id: ingressId,
19030
+ selection: toArcubaseSelection(selection),
19031
+ })
19032
+ },`);
19033
+ }
19034
+ if (hasAction(ingress, "bulk_update")) {
19035
+ methodChunks.push(` async bulkUpdate(selection: ${typeName}Selection, fields: ${typeName}BulkUpdateField[]): Promise<{ updated: number }> {
19036
+ return runtime.request<{ updated: number }>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/bulk-update\`, {
19037
+ policy_id: ingressId,
19038
+ selection: toArcubaseSelection(selection),
19039
+ fields: fields.map((field) => ({
19040
+ id: fieldIds[field.key],
19041
+ action: field.action,
19042
+ })),
19043
+ })
19044
+ },
19045
+
19046
+ async saveBulkUpdate(input: { name: string; subject: string; fields: ${typeName}BulkUpdateField[] }): Promise<string> {
19047
+ return runtime.request<string>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/bulk-update-save-as\`, {
19048
+ name: input.name,
19049
+ subject: input.subject,
19050
+ fields: input.fields.map((field) => ({
19051
+ id: fieldIds[field.key],
19052
+ action: field.action,
19053
+ })),
19054
+ })
19055
+ },`);
19056
+ }
19057
+ if (hasAction(ingress, "export")) {
19058
+ methodChunks.push(` async exportRows(options: ${typeName}ExportOptions = {}): Promise<{ task_id: string }> {
19059
+ const fieldKeys = options.fields ?? Object.keys(fieldIds) as ${typeName}FieldKey[]
19060
+ return runtime.request<{ task_id: string }>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/export\`, {
19061
+ policy_id: ingressId,
19062
+ props: options.props ?? [],
19063
+ fields: fieldKeys.map((key) => fieldIds[key]),
19064
+ propnames: options.propNames ?? {},
19065
+ options: { has_id: options.hasIdField ?? false },
19066
+ })
19067
+ },
19068
+
19069
+ async exportTask(taskId: string): Promise<Record<string, any>> {
19070
+ return runtime.request<Record<string, any>>('GET', \`/export-task/\${taskId}\`)
19071
+ },`);
19072
+ }
19073
+ if (hasAction(ingress, "batch_print")) {
19074
+ methodChunks.push(` async batchPrint(selection: ${typeName}Selection, params: { limit?: number; offset?: number } = {}): Promise<{ items?: Record<string, any>[]; total?: number }> {
19075
+ return runtime.request<{ items?: Record<string, any>[]; total?: number }>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/selection-query/batch_print\`, {
19076
+ ...params,
19077
+ policy_id: ingressId,
19078
+ selection: toArcubaseSelection(selection),
19079
+ })
19080
+ },`);
19081
+ }
19082
+ if (hasAction(ingress, "archive")) {
19083
+ methodChunks.push(` async archive(selection: ${typeName}Selection): Promise<{ archived?: number } | boolean> {
19084
+ return runtime.request<{ archived?: number } | boolean>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/selection-query/archive\`, {
19085
+ policy_id: ingressId,
19086
+ selection: toArcubaseSelection(selection),
19087
+ })
19088
+ },`);
19089
+ }
19090
+ if (hasAction(ingress, "tag_manage")) {
19091
+ methodChunks.push(` tags: {
19092
+ async list(): Promise<string[]> {
19093
+ return runtime.request<string[]>('GET', \`/user-action-entity/${ingress.appId}/${ingress.entity.id}/tag-names\`)
19094
+ },
19095
+ async add(selection: ${typeName}Selection, tagNames: string[]): Promise<Record<string, any>> {
19096
+ return runtime.request<Record<string, any>>('POST', \`/user-action-entity/${ingress.appId}/${ingress.entity.id}/batch-add-tags\`, {
19097
+ policy_id: ingressId,
19098
+ selection: toArcubaseSelection(selection),
19099
+ tag_names: tagNames,
19100
+ })
19101
+ },
19102
+ async remove(selection: ${typeName}Selection, tagNames: string[]): Promise<boolean> {
19103
+ return runtime.request<boolean>('POST', \`/user-action-entity/${ingress.appId}/${ingress.entity.id}/batch-remove-tags\`, {
19104
+ policy_id: ingressId,
19105
+ selection: toArcubaseSelection(selection),
19106
+ tag_names: tagNames,
19107
+ })
19108
+ },
19109
+ async selection(selection: ${typeName}Selection): Promise<string[]> {
19110
+ return runtime.request<string[]>('POST', \`/user-action-entity/${ingress.appId}/${ingress.entity.id}/get-selection-tags\`, {
19111
+ policy_id: ingressId,
19112
+ selection: toArcubaseSelection(selection),
19113
+ })
19114
+ },
19115
+ },`);
19116
+ }
19117
+ const customActions = ingress.actions.filter((action) => !["view", "add", "edit", "delete", "bulk_update", "export", "batch_print", "archive", "tag_manage"].includes(action));
19118
+ if (customActions.length > 0) {
19119
+ methodChunks.push(` async action(action: ${typeName}CustomAction, payload: Record<string, any> = {}): Promise<Record<string, any>> {
19120
+ if (!allowedActions.includes(action)) {
19121
+ throw new Error(\`Action is not allowed for ${ingress.key}: \${action}\`)
19122
+ }
19123
+ return runtime.request<Record<string, any>>('POST', \`/entity/${ingress.appId}/${ingress.entity.id}/selection-query/\${encodeURIComponent(action)}\`, {
19124
+ ...payload,
19125
+ policy_id: ingressId,
19126
+ selection: payload.selection ? toArcubaseSelection(payload.selection) : undefined,
19127
+ })
19128
+ },`);
19129
+ }
19130
+ return `import {
19131
+ fromArcubaseFields,
19132
+ mapArcubaseCondition,
19133
+ mapArcubaseSorts,
19134
+ toArcubaseFields,
19135
+ type ArcubaseRow,
19136
+ type ArcubaseRuntime,
19137
+ } from '../runtime.js'
19138
+
19139
+ export type ${typeName}FieldKey = ${fields.map((field) => `'${field.key}'`).join(" | ")}
18888
19140
 
18889
19141
  export type ${typeName}Fields = {
18890
19142
  ${fieldLines.join("\n")}
@@ -18892,126 +19144,127 @@ ${fieldLines.join("\n")}
18892
19144
 
18893
19145
  export type ${typeName}CreateInput = ${typeName}Fields
18894
19146
  export type ${typeName}UpdateInput = Partial<${typeName}Fields>
19147
+ export type ${typeName}Action = ${ingress.actions.map((action) => `'${action}'`).join(" | ") || "never"}
19148
+ export type ${typeName}CustomAction = ${customActions.map((action) => `'${action}'`).join(" | ") || "never"}
18895
19149
 
18896
- const entityId = ${entity.id}
18897
- const fieldIds = {
18898
- ${fieldMapLines.join("\n")}
18899
- } as const
19150
+ export type ${typeName}Sort = {
19151
+ column: ${typeName}FieldKey | 'id' | 'created_at' | 'updated_at' | 'creator' | string
19152
+ order: 'asc' | 'desc'
19153
+ }
18900
19154
 
18901
- function toArcubaseFields(fields: Partial<${typeName}Fields>): Record<string, any> {
18902
- const out: Record<string, any> = {}
18903
- for (const [key, value] of Object.entries(fields)) {
18904
- if (value === undefined) continue
18905
- const fieldId = fieldIds[key as keyof typeof fieldIds]
18906
- if (!fieldId) {
18907
- throw new Error(\`Unknown ${entity.sdkName} field: \${key}\`)
18908
- }
18909
- out[String(fieldId)] = value
18910
- }
18911
- return out
19155
+ export type ${typeName}QueryParams = {
19156
+ limit?: number
19157
+ offset?: number
19158
+ search?: Record<string, any>
19159
+ sorts?: ${typeName}Sort[]
19160
+ view_mode?: 'normal' | 'deleted' | 'archived'
19161
+ withSubForm?: boolean
18912
19162
  }
18913
19163
 
18914
- function fromArcubaseFields(raw: Record<string, any> | undefined): ${typeName}Fields {
18915
- const out: Record<string, any> = {}
18916
- const source = raw ?? {}
18917
- for (const [key, fieldId] of Object.entries(fieldIds)) {
18918
- if (String(fieldId) in source) {
18919
- out[key] = source[String(fieldId)]
18920
- }
18921
- }
18922
- return out as ${typeName}Fields
19164
+ export type ${typeName}Selection = {
19165
+ type: 'ids' | 'condition'
19166
+ length?: number
19167
+ ids?: Array<number | string>
19168
+ condition?: Record<string, any>
19169
+ sorts?: ${typeName}Sort[]
19170
+ }
19171
+
19172
+ export type ${typeName}BulkUpdateField = {
19173
+ key: ${typeName}FieldKey
19174
+ action: Record<string, any>
18923
19175
  }
18924
19176
 
19177
+ export type ${typeName}ExportOptions = {
19178
+ fields?: ${typeName}FieldKey[]
19179
+ props?: string[]
19180
+ propNames?: Record<string, string>
19181
+ hasIdField?: boolean
19182
+ }
19183
+
19184
+ const ingressId = ${JSON.stringify(ingress.hashId)}
19185
+ const fieldIds = {
19186
+ ${fieldMapLines.join("\n")}
19187
+ } as const
19188
+ const allowedActions = ${JSON.stringify(customActions)} as const
19189
+
18925
19190
  function mapRow(raw: Record<string, any>): ArcubaseRow<${typeName}Fields> {
18926
19191
  return {
18927
19192
  id: Number(raw.id),
18928
19193
  title: typeof raw.title === 'string' ? raw.title : undefined,
18929
- fields: fromArcubaseFields(raw.fields),
19194
+ fields: fromArcubaseFields<${typeName}Fields>(raw.fields, fieldIds),
18930
19195
  raw,
18931
19196
  }
18932
19197
  }
18933
19198
 
18934
- export function create${typeName}SDK(runtime: ArcubaseRuntime) {
19199
+ function toArcubaseSelection(selection: ${typeName}Selection): Record<string, any> {
18935
19200
  return {
18936
- async create(fields: ${typeName}CreateInput): Promise<number> {
18937
- return runtime.request<number>('POST', \`/entity/${entity.appId}/\${entityId}/insert\`, {
18938
- fields: toArcubaseFields(fields),
18939
- })
18940
- },
18941
-
18942
- async update(rowId: string | number, fields: ${typeName}UpdateInput): Promise<boolean> {
18943
- const data = toArcubaseFields(fields)
18944
- return runtime.request<boolean>('PUT', \`/entity/${entity.appId}/\${entityId}/row/\${rowId}\`, {
18945
- data,
18946
- changed_fields: Object.keys(data).map((fieldId) => Number(fieldId)),
18947
- })
18948
- },
18949
-
18950
- async get(rowId: string | number): Promise<ArcubaseRow<${typeName}Fields>> {
18951
- const data = await runtime.request<{ record?: Record<string, any> }>('GET', \`/entity/${entity.appId}/\${entityId}/row/\${rowId}\`)
18952
- return mapRow(data.record ?? {})
18953
- },
18954
-
18955
- async query(params: { limit?: number; offset?: number; search?: Record<string, any> } = {}): Promise<{ items: ArcubaseRow<${typeName}Fields>[]; total?: number }> {
18956
- const data = await runtime.request<{ items?: Record<string, any>[]; total?: number }>('POST', \`/entity/${entity.appId}/\${entityId}/data-query\`, params)
18957
- return {
18958
- items: (data.items ?? []).map(mapRow),
18959
- total: data.total,
18960
- }
18961
- },
19201
+ ...selection,
19202
+ condition: mapArcubaseCondition(selection.condition ?? {}, fieldIds),
19203
+ sorts: mapArcubaseSorts(selection.sorts, fieldIds),
18962
19204
  }
18963
19205
  }
19206
+
19207
+ export function create${typeName}Ingress(runtime: ArcubaseRuntime) {
19208
+ return {
19209
+ ${methodLines(methodChunks)} }
19210
+ }
18964
19211
  `;
18965
19212
  }
18966
- function emitClient(entities) {
18967
- const imports = entities.map((entity) => {
18968
- const typeName = toPascalCase(entity.sdkName);
18969
- return `import { create${typeName}SDK } from './entities/${entity.sdkName}.js'`;
19213
+ function emitClient(ingresses) {
19214
+ const imports = ingresses.map((ingress) => {
19215
+ const typeName = toPascalCase(ingress.key);
19216
+ return `import { create${typeName}Ingress } from './ingresses/${ingress.key}.js'`;
18970
19217
  });
18971
- const properties = entities.map((entity) => ` ${entity.sdkName}: create${toPascalCase(entity.sdkName)}SDK(runtime),`);
18972
- return `import { createRuntime, type ArcubaseSdkConfig } from './runtime.js'
19218
+ const mapLines = ingresses.map((ingress) => ` ${JSON.stringify(ingress.key)}: ReturnType<typeof create${toPascalCase(ingress.key)}Ingress>`);
19219
+ const cases = ingresses.map((ingress) => ` case ${JSON.stringify(ingress.key)}:
19220
+ return create${toPascalCase(ingress.key)}Ingress(runtime) as ArcubaseIngressMap[K]`);
19221
+ return `import { createRuntime, type ArcubaseClientConfig } from './runtime.js'
18973
19222
  ${imports.join("\n")}
18974
19223
 
18975
- export function createArcubaseSdk(config: ArcubaseSdkConfig) {
19224
+ export type ArcubaseIngressMap = {
19225
+ ${mapLines.join("\n")}
19226
+ }
19227
+
19228
+ export type ArcubaseIngressKey = keyof ArcubaseIngressMap
19229
+
19230
+ export function createArcubaseClient(config: ArcubaseClientConfig) {
18976
19231
  const runtime = createRuntime(config)
18977
19232
  return {
18978
- ${properties.join("\n")}
19233
+ ingress<K extends ArcubaseIngressKey>(key: K): ArcubaseIngressMap[K] {
19234
+ switch (key) {
19235
+ ${cases.join("\n")}
19236
+ default:
19237
+ throw new Error(\`Unknown Arcubase ingress: \${String(key)}\`)
19238
+ }
19239
+ },
18979
19240
  }
18980
19241
  }
18981
19242
  `;
18982
19243
  }
18983
- function emitIndex(entities) {
18984
- return `export { createArcubaseSdk } from './client.js'
18985
- export type { ArcubaseSdkConfig, ArcubaseRow } from './runtime.js'
19244
+ function emitIndex(ingresses) {
19245
+ return `export { createArcubaseClient } from './client.js'
19246
+ export type { ArcubaseClientConfig, ArcubaseRow } from './runtime.js'
18986
19247
  export { arcubaseSchema } from './schema.js'
18987
- ${entities.map((entity) => `export type { ${toPascalCase(entity.sdkName)}Fields, ${toPascalCase(entity.sdkName)}CreateInput, ${toPascalCase(entity.sdkName)}UpdateInput } from './entities/${entity.sdkName}.js'`).join("\n")}
19248
+ export type { ArcubaseIngressKey, ArcubaseIngressMap } from './client.js'
19249
+ ${ingresses.map((ingress) => {
19250
+ const typeName = toPascalCase(ingress.key);
19251
+ return `export type { ${typeName}Fields, ${typeName}CreateInput, ${typeName}UpdateInput, ${typeName}FieldKey, ${typeName}Selection } from './ingresses/${ingress.key}.js'`;
19252
+ }).join("\n")}
18988
19253
  `;
18989
19254
  }
18990
19255
  function generateArcubaseProjectSDK(payload) {
18991
- const entities = normalizeEntities(payload);
19256
+ const ingresses = normalizeIngresses(payload);
18992
19257
  return {
18993
19258
  files: [
18994
19259
  { path: "runtime.ts", contents: emitRuntime() },
18995
- { path: "schema.ts", contents: emitSchema(entities) },
18996
- ...entities.map((entity) => ({ path: `entities/${entity.sdkName}.ts`, contents: emitEntity(entity) })),
18997
- { path: "client.ts", contents: emitClient(entities) },
18998
- { path: "index.ts", contents: emitIndex(entities) }
19260
+ { path: "schema.ts", contents: emitSchema(ingresses) },
19261
+ ...ingresses.map((ingress) => ({ path: `ingresses/${ingress.key}.ts`, contents: emitIngress(ingress) })),
19262
+ { path: "client.ts", contents: emitClient(ingresses) },
19263
+ { path: "index.ts", contents: emitIndex(ingresses) }
18999
19264
  ]
19000
19265
  };
19001
19266
  }
19002
19267
 
19003
- // src/runtime/dev_sdk_gen.ts
19004
- function generateArcubaseProjectSDK2(payload) {
19005
- try {
19006
- return generateArcubaseProjectSDK(payload);
19007
- } catch (error51) {
19008
- if (error51 instanceof ArcubaseCodeGenError) {
19009
- throw new CLIError(error51.code, error51.message, 2);
19010
- }
19011
- throw error51;
19012
- }
19013
- }
19014
-
19015
19268
  // src/runtime/execute.ts
19016
19269
  function renderRootHelp(scope) {
19017
19270
  const binary = scope === "admin" ? "arcubase-admin" : "arcubase";
@@ -19243,10 +19496,10 @@ function renderDevSDKGenHelp() {
19243
19496
  " - arcubase-admin dev sdk-gen --app-id <app_id> --out src/arcubase",
19244
19497
  "",
19245
19498
  "requirements:",
19499
+ " - every generated ingress must have a configured ingress.key; sdk-gen fails fast when keys are missing",
19246
19500
  " - every generated field must have a configured field.key; sdk-gen fails fast when keys are missing",
19247
- " - existing field.key values must be stable unique TypeScript identifiers",
19248
- " - entity property names use entity.key when available, otherwise a stable entity<id> fallback",
19249
- " - generated code accepts createArcubaseSdk({ baseURL, accessToken, refreshToken })"
19501
+ " - ingress.key and field.key values must be stable unique TypeScript identifiers",
19502
+ ' - generated code accepts createArcubaseClient({ baseURL, accessToken, refreshToken }).ingress("<IngressKey>")'
19250
19503
  ].join("\n");
19251
19504
  }
19252
19505
  function resolveEndpoint(command, flags) {
@@ -20788,6 +21041,85 @@ function assertSDKGenFieldKeysPresent(entity) {
20788
21041
  ]
20789
21042
  });
20790
21043
  }
21044
+ function extractSDKGenIngressRefs(payload) {
21045
+ const data = unwrapResponseData(payload);
21046
+ const source = Array.isArray(data) ? data : isRecord4(data) && Array.isArray(data.list) ? data.list : [];
21047
+ return source.filter((item) => isRecord4(item));
21048
+ }
21049
+ function ingressKeyOf(ingress) {
21050
+ return typeof ingress.key === "string" ? ingress.key.trim() : "";
21051
+ }
21052
+ function ingressHashIDOf(ingress) {
21053
+ if (typeof ingress.hash_id === "string" && ingress.hash_id.trim()) {
21054
+ return ingress.hash_id.trim();
21055
+ }
21056
+ if (typeof ingress.hashId === "string" && ingress.hashId.trim()) {
21057
+ return ingress.hashId.trim();
21058
+ }
21059
+ return "";
21060
+ }
21061
+ function assertSDKGenIngressesReady(ingresses) {
21062
+ if (ingresses.length === 0) {
21063
+ throw new CLIError("SDK_GEN_NO_INGRESSES", "sdk-gen could not find ingress definitions for this app", 2, {
21064
+ operation: "dev sdk-gen",
21065
+ suggestions: ["create at least one access rule with a stable ingress.key before running sdk-gen"]
21066
+ });
21067
+ }
21068
+ const seen = /* @__PURE__ */ new Set();
21069
+ const missingKey = [];
21070
+ const missingHash = [];
21071
+ const invalidKey = [];
21072
+ const duplicateKey = [];
21073
+ for (const ingress of ingresses) {
21074
+ const key = ingressKeyOf(ingress);
21075
+ if (!key) {
21076
+ missingKey.push(ingress);
21077
+ continue;
21078
+ }
21079
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(key)) {
21080
+ invalidKey.push(key);
21081
+ }
21082
+ if (seen.has(key)) {
21083
+ duplicateKey.push(key);
21084
+ }
21085
+ seen.add(key);
21086
+ if (!ingressHashIDOf(ingress)) {
21087
+ missingHash.push(ingress);
21088
+ }
21089
+ }
21090
+ if (missingKey.length > 0) {
21091
+ const preview = missingKey.slice(0, 8).map((ingress) => String(ingress.name ?? ingress.id ?? "unnamed ingress"));
21092
+ const suffix = missingKey.length > preview.length ? `, and ${missingKey.length - preview.length} more` : "";
21093
+ throw new CLIError("SDK_GEN_INGRESS_KEY_REQUIRED", `missing ingress.key values: ${preview.join(", ")}${suffix}`, 2, {
21094
+ operation: "dev sdk-gen",
21095
+ issues: missingKey.map((ingress) => ({
21096
+ path: `ingress.${String(ingress.id ?? "unknown")}.key`,
21097
+ message: `ingress.key is required for ${String(ingress.name ?? ingress.id ?? "unnamed ingress")}`
21098
+ })),
21099
+ suggestions: [
21100
+ "set stable ingress.key values in Arcubase admin before running sdk-gen",
21101
+ "rerun arcubase-admin dev sdk-gen after ingress keys are complete"
21102
+ ]
21103
+ });
21104
+ }
21105
+ if (invalidKey.length > 0) {
21106
+ throw new CLIError("SDK_GEN_INVALID_INGRESS_KEY", `invalid ingress.key values: ${invalidKey.join(", ")}`, 2, {
21107
+ operation: "dev sdk-gen",
21108
+ suggestions: ["use TypeScript identifier keys such as publicEntry or customerPortal"]
21109
+ });
21110
+ }
21111
+ if (duplicateKey.length > 0) {
21112
+ throw new CLIError("SDK_GEN_DUPLICATE_INGRESS_KEY", `duplicate ingress.key values: ${duplicateKey.join(", ")}`, 2, {
21113
+ operation: "dev sdk-gen"
21114
+ });
21115
+ }
21116
+ if (missingHash.length > 0) {
21117
+ throw new CLIError("SDK_GEN_INGRESS_HASH_ID_REQUIRED", "sdk-gen expected hash_id for every ingress definition", 2, {
21118
+ operation: "dev sdk-gen",
21119
+ suggestions: ["upgrade Arcubase server so admin access-rule list returns hash_id"]
21120
+ });
21121
+ }
21122
+ }
20791
21123
  async function executeDevSDKGen(runtimeEnv, flags, fetchImpl) {
20792
21124
  validateDevSDKGenFlags(flags);
20793
21125
  const appId = flagValue(flags, "app-id");
@@ -20814,7 +21146,7 @@ async function executeDevSDKGen(runtimeEnv, flags, fetchImpl) {
20814
21146
  if (entityRefs.length === 0) {
20815
21147
  throw new CLIError("SDK_GEN_NO_ENTITIES", "sdk-gen could not find entities in app detail response", 2);
20816
21148
  }
20817
- const entities = [];
21149
+ const ingresses = [];
20818
21150
  for (const entityRef of entityRefs) {
20819
21151
  const entityEndpoint = `/api/apps/${encodeURIComponent(appId)}/entity/${encodeURIComponent(entityRef.id)}`;
20820
21152
  const entityDetail = await requestJSON(runtimeEnv, "GET", entityEndpoint, void 0, fetchImpl);
@@ -20823,12 +21155,21 @@ async function executeDevSDKGen(runtimeEnv, flags, fetchImpl) {
20823
21155
  throw new CLIError("SDK_GEN_INVALID_SCHEMA", "sdk-gen expected entity detail response data", 2);
20824
21156
  }
20825
21157
  assertSDKGenFieldKeysPresent(entityPayload);
20826
- entities.push(entityPayload);
20827
- }
20828
- const generated = generateArcubaseProjectSDK2({
21158
+ const ingressEndpoint = `/api/apps/${encodeURIComponent(appId)}/entity/${encodeURIComponent(entityRef.id)}/ingress`;
21159
+ const ingressList = await requestJSON(runtimeEnv, "GET", ingressEndpoint, void 0, fetchImpl);
21160
+ const entityIngresses = extractSDKGenIngressRefs(ingressList.data).map((ingress) => ({
21161
+ ...ingress,
21162
+ hash_id: ingressHashIDOf(ingress),
21163
+ key: ingressKeyOf(ingress),
21164
+ entity: entityPayload
21165
+ }));
21166
+ ingresses.push(...entityIngresses);
21167
+ }
21168
+ assertSDKGenIngressesReady(ingresses);
21169
+ const generated = generateArcubaseProjectSDK({
20829
21170
  id: resolveSDKGenAppId(appId, appPayload),
20830
21171
  name: typeof appPayload.name === "string" ? appPayload.name : void 0,
20831
- entities
21172
+ ingresses
20832
21173
  });
20833
21174
  const absoluteOutDir = path2.resolve(process.cwd(), outDir);
20834
21175
  for (const file2 of generated.files) {