@antlur/backstage 1.12.12 → 1.12.14

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.
Files changed (43) hide show
  1. package/dist/cli/actions/sync-blueprints.d.ts +3 -0
  2. package/dist/cli/actions/sync-blueprints.d.ts.map +1 -0
  3. package/dist/cli/actions/sync-blueprints.js +42 -0
  4. package/dist/cli/cli.js +8 -2
  5. package/dist/client.d.ts +2 -0
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +3 -0
  8. package/dist/config.d.ts +26 -0
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/endpoints/blueprints.d.ts +37 -0
  11. package/dist/endpoints/blueprints.d.ts.map +1 -0
  12. package/dist/endpoints/blueprints.js +27 -0
  13. package/dist/index.d.ts +1 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -0
  16. package/dist/studio/define-blueprint.d.ts +3 -0
  17. package/dist/studio/define-blueprint.d.ts.map +1 -0
  18. package/dist/studio/define-blueprint.js +3 -0
  19. package/dist/studio/index.d.ts +1 -0
  20. package/dist/studio/index.d.ts.map +1 -1
  21. package/dist/studio/index.js +1 -0
  22. package/dist/studio/types/block.d.ts +9 -2
  23. package/dist/studio/types/block.d.ts.map +1 -1
  24. package/dist/studio/types/field.d.ts +23 -1
  25. package/dist/studio/types/field.d.ts.map +1 -1
  26. package/dist/studio/types/layout.d.ts +9 -2
  27. package/dist/studio/types/layout.d.ts.map +1 -1
  28. package/dist/types/blueprint.d.ts +25 -1
  29. package/dist/types/blueprint.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/readme.md +199 -4
  32. package/src/cli/actions/sync-blueprints.ts +45 -0
  33. package/src/cli/cli.ts +9 -2
  34. package/src/client.ts +3 -0
  35. package/src/config.ts +24 -0
  36. package/src/endpoints/blueprints.ts +58 -0
  37. package/src/index.ts +1 -0
  38. package/src/studio/define-blueprint.ts +5 -0
  39. package/src/studio/index.ts +1 -0
  40. package/src/studio/types/block.ts +13 -4
  41. package/src/studio/types/field.ts +28 -4
  42. package/src/studio/types/layout.ts +13 -4
  43. package/src/types/blueprint.ts +23 -1
@@ -0,0 +1,3 @@
1
+ import type { BackstageUserConfig } from "../../config.js";
2
+ export declare function syncBlueprints(config: BackstageUserConfig): Promise<void>;
3
+ //# sourceMappingURL=sync-blueprints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-blueprints.d.ts","sourceRoot":"","sources":["../../../src/cli/actions/sync-blueprints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,wBAAsB,cAAc,CAAC,MAAM,EAAE,mBAAmB,iBAyC/D"}
@@ -0,0 +1,42 @@
1
+ import { BackstageClient } from "../../client.js";
2
+ export async function syncBlueprints(config) {
3
+ const client = new BackstageClient(config);
4
+ if (!config.blueprints || !config.blueprints.length) {
5
+ console.log("No blueprints found in config");
6
+ return;
7
+ }
8
+ const syncPromises = config.blueprints.map(async (blueprint) => {
9
+ const blueprintData = {
10
+ name: blueprint.name,
11
+ slug: blueprint.slug,
12
+ slug_single: blueprint.slug_single,
13
+ description: blueprint.description,
14
+ is_routable: blueprint.is_routable,
15
+ has_location: blueprint.has_location,
16
+ has_route_index: blueprint.has_route_index,
17
+ fields: blueprint.fields,
18
+ };
19
+ try {
20
+ await client.blueprints.create(blueprintData);
21
+ console.log(`✓ Blueprint ${blueprint.slug} created`);
22
+ }
23
+ catch (err) {
24
+ if (err?.response?.status === 409) {
25
+ const id = err.response.data;
26
+ console.log(`⚠ Blueprint ${blueprint.slug} already exists with id ${id}. Updating...`);
27
+ try {
28
+ await client.blueprints.update(id, blueprintData);
29
+ console.log(`✓ Blueprint ${blueprint.slug} updated`);
30
+ }
31
+ catch (updateErr) {
32
+ console.error(`✗ Failed to update blueprint ${blueprint.slug}:`, updateErr?.message || updateErr);
33
+ }
34
+ }
35
+ else {
36
+ console.error(`✗ Failed to create blueprint ${blueprint.slug}:`, err?.message || err);
37
+ }
38
+ }
39
+ });
40
+ await Promise.all(syncPromises);
41
+ console.log(`\nSync complete: ${config.blueprints.length} blueprint(s) processed`);
42
+ }
package/dist/cli/cli.js CHANGED
@@ -4,6 +4,7 @@ import { resolve } from "path";
4
4
  import { program } from "commander";
5
5
  import { loadBackstageConfig } from "./load-config.js";
6
6
  import { syncBlocks } from "./actions/sync-blocks.js";
7
+ import { syncBlueprints } from "./actions/sync-blueprints.js";
7
8
  import { syncLayouts } from "./actions/sync-layouts.js";
8
9
  config({ path: resolve(process.cwd(), ".env") });
9
10
  program
@@ -12,7 +13,7 @@ program
12
13
  .version(process.env.npm_package_version || "1.0.0");
13
14
  program
14
15
  .command("sync <type>")
15
- .description("Sync blocks and layouts with the Backstage CMS")
16
+ .description("Sync blocks, blueprints, and layouts with the Backstage CMS")
16
17
  .action(async (type) => {
17
18
  const backstageConfig = await loadBackstageConfig();
18
19
  if (!backstageConfig) {
@@ -23,16 +24,21 @@ program
23
24
  await syncBlocks(backstageConfig);
24
25
  return;
25
26
  }
27
+ if (type === "blueprints") {
28
+ await syncBlueprints(backstageConfig);
29
+ return;
30
+ }
26
31
  if (type === "layouts") {
27
32
  await syncLayouts(backstageConfig);
28
33
  return;
29
34
  }
30
35
  if (type === "all") {
31
36
  await syncBlocks(backstageConfig);
37
+ await syncBlueprints(backstageConfig);
32
38
  await syncLayouts(backstageConfig);
33
39
  return;
34
40
  }
35
- console.error(`Unknown type: ${type}. Valid types are: blocks, layouts, all`);
41
+ console.error(`Unknown type: ${type}. Valid types are: blocks, blueprints, layouts, all`);
36
42
  process.exit(1);
37
43
  });
38
44
  program.parse();
package/dist/client.d.ts CHANGED
@@ -2,6 +2,7 @@ import { BackstageUserConfig } from "./config.js";
2
2
  import { AlertService } from "./endpoints/alerts.js";
3
3
  import { AuthService } from "./endpoints/auth.js";
4
4
  import { BlocksService } from "./endpoints/blocks.js";
5
+ import { BlueprintsService } from "./endpoints/blueprints.js";
5
6
  import { EntryService } from "./endpoints/entries.js";
6
7
  import { EventService } from "./endpoints/events.js";
7
8
  import { FormService } from "./endpoints/forms.js";
@@ -24,6 +25,7 @@ export declare class BackstageClient {
24
25
  readonly alerts: AlertService;
25
26
  readonly auth: AuthService;
26
27
  readonly blocks: BlocksService;
28
+ readonly blueprints: BlueprintsService;
27
29
  readonly entries: EntryService;
28
30
  readonly events: EventService;
29
31
  readonly forms: FormService;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -2,6 +2,7 @@ import { getGlobalConfig } from "./config.js";
2
2
  import { AlertService } from "./endpoints/alerts.js";
3
3
  import { AuthService } from "./endpoints/auth.js";
4
4
  import { BlocksService } from "./endpoints/blocks.js";
5
+ import { BlueprintsService } from "./endpoints/blueprints.js";
5
6
  import { EntryService } from "./endpoints/entries.js";
6
7
  import { EventService } from "./endpoints/events.js";
7
8
  import { FormService } from "./endpoints/forms.js";
@@ -25,6 +26,7 @@ export class BackstageClient {
25
26
  alerts;
26
27
  auth;
27
28
  blocks;
29
+ blueprints;
28
30
  entries;
29
31
  events;
30
32
  forms;
@@ -61,6 +63,7 @@ export class BackstageClient {
61
63
  this.alerts = new AlertService(this);
62
64
  this.auth = new AuthService(this);
63
65
  this.blocks = new BlocksService(this);
66
+ this.blueprints = new BlueprintsService(this);
64
67
  this.entries = new EntryService(this);
65
68
  this.events = new EventService(this);
66
69
  this.forms = new FormService(this);
package/dist/config.d.ts CHANGED
@@ -1,9 +1,35 @@
1
1
  import type { BlockDefinition } from "./studio/types/index.js";
2
+ export interface BlueprintDefinition {
3
+ name: string;
4
+ slug: string;
5
+ slug_single?: string;
6
+ description?: string;
7
+ is_routable?: boolean;
8
+ has_location?: boolean;
9
+ has_route_index?: boolean;
10
+ fields: Array<{
11
+ name: string;
12
+ slug: string;
13
+ type: string;
14
+ type_id?: string | null;
15
+ is_primary?: boolean;
16
+ is_multiple?: boolean;
17
+ show_in_list?: boolean;
18
+ order: number;
19
+ allowed_references?: string[];
20
+ options?: Array<{
21
+ label: string;
22
+ value: any;
23
+ }>;
24
+ placeholder?: string;
25
+ }>;
26
+ }
2
27
  export interface BackstageUserConfig {
3
28
  accountId?: string | undefined;
4
29
  token?: string | undefined;
5
30
  baseURL?: string;
6
31
  blocks?: BlockDefinition<any>[] | undefined;
32
+ blueprints?: BlueprintDefinition[] | undefined;
7
33
  layouts?: any[] | undefined;
8
34
  onError?: (error: Error) => void;
9
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,CAAC;IAC5C,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAQD,wBAAgB,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAM7E;AAED,wBAAgB,eAAe,IAAI,mBAAmB,CAGrD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,GAAG,CAAA;SAAE,CAAC,CAAC;QAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,CAAC;IAC5C,UAAU,CAAC,EAAE,mBAAmB,EAAE,GAAG,SAAS,CAAC;IAC/C,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAQD,wBAAgB,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAM7E;AAED,wBAAgB,eAAe,IAAI,mBAAmB,CAGrD"}
@@ -0,0 +1,37 @@
1
+ import type { Blueprint } from "../types/blueprint";
2
+ import { BaseService } from "./base.js";
3
+ export interface CreateBlueprintParams {
4
+ name: string;
5
+ slug: string;
6
+ slug_single?: string;
7
+ description?: string;
8
+ is_routable?: boolean;
9
+ has_location?: boolean;
10
+ has_route_index?: boolean;
11
+ fields: Array<{
12
+ name: string;
13
+ slug: string;
14
+ type: string;
15
+ type_id?: string | null;
16
+ is_primary?: boolean;
17
+ is_multiple?: boolean;
18
+ show_in_list?: boolean;
19
+ order: number;
20
+ allowed_references?: string[];
21
+ options?: Array<{
22
+ label: string;
23
+ value: any;
24
+ }>;
25
+ placeholder?: string;
26
+ }>;
27
+ }
28
+ export interface UpdateBlueprintParams extends Partial<CreateBlueprintParams> {
29
+ }
30
+ export declare class BlueprintsService extends BaseService {
31
+ list(options?: RequestInit): Promise<Blueprint[]>;
32
+ get(id: string, options?: RequestInit): Promise<Blueprint | null>;
33
+ create(params: CreateBlueprintParams, options?: RequestInit): Promise<Blueprint>;
34
+ update(id: string, params: UpdateBlueprintParams, options?: RequestInit): Promise<Blueprint>;
35
+ delete(id: string, options?: RequestInit): Promise<void>;
36
+ }
37
+ //# sourceMappingURL=blueprints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprints.d.ts","sourceRoot":"","sources":["../../src/endpoints/blueprints.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,GAAG,CAAA;SAAE,CAAC,CAAC;QAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,qBAAsB,SAAQ,OAAO,CAAC,qBAAqB,CAAC;CAAG;AAEhF,qBAAa,iBAAkB,SAAQ,WAAW;IAC1C,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAKjD,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IASjE,MAAM,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IAKhF,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IAK5F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/D"}
@@ -0,0 +1,27 @@
1
+ import { BaseService } from "./base.js";
2
+ export class BlueprintsService extends BaseService {
3
+ async list(options) {
4
+ const { data } = await this.client.get("/blueprints", options);
5
+ return data;
6
+ }
7
+ async get(id, options) {
8
+ try {
9
+ const { data } = await this.client.get(`/blueprints/${id}`, options);
10
+ return data;
11
+ }
12
+ catch (error) {
13
+ return null;
14
+ }
15
+ }
16
+ async create(params, options) {
17
+ const { data } = await this.client.post("/blueprints", params, options);
18
+ return data;
19
+ }
20
+ async update(id, params, options) {
21
+ const { data } = await this.client.put(`/blueprints/${id}`, params, options);
22
+ return data;
23
+ }
24
+ async delete(id, options) {
25
+ await this.client.delete(`/blueprints/${id}`, options);
26
+ }
27
+ }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { BackstageClient } from "./client.js";
3
3
  export * from "./endpoints/alerts.js";
4
4
  export * from "./endpoints/auth.js";
5
5
  export * from "./endpoints/blocks.js";
6
+ export * from "./endpoints/blueprints.js";
6
7
  export * from "./endpoints/entries.js";
7
8
  export * from "./endpoints/events.js";
8
9
  export * from "./endpoints/forms.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG5D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG5D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ export { BackstageClient } from "./client.js";
6
6
  export * from "./endpoints/alerts.js";
7
7
  export * from "./endpoints/auth.js";
8
8
  export * from "./endpoints/blocks.js";
9
+ export * from "./endpoints/blueprints.js";
9
10
  export * from "./endpoints/entries.js";
10
11
  export * from "./endpoints/events.js";
11
12
  export * from "./endpoints/forms.js";
@@ -0,0 +1,3 @@
1
+ import type { BlueprintDefinition } from "../config.js";
2
+ export declare function defineBlueprint(blueprint: BlueprintDefinition): BlueprintDefinition;
3
+ //# sourceMappingURL=define-blueprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-blueprint.d.ts","sourceRoot":"","sources":["../../src/studio/define-blueprint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,wBAAgB,eAAe,CAAC,SAAS,EAAE,mBAAmB,GAAG,mBAAmB,CAEnF"}
@@ -0,0 +1,3 @@
1
+ export function defineBlueprint(blueprint) {
2
+ return blueprint;
3
+ }
@@ -1,5 +1,6 @@
1
1
  export * from "./types";
2
2
  export * from "./define-block";
3
+ export * from "./define-blueprint";
3
4
  export * from "./define-field";
4
5
  export * from "./define-layout";
5
6
  export * from "./define-schema";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/studio/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/studio/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export * from "./types";
2
2
  export * from "./define-block";
3
+ export * from "./define-blueprint";
3
4
  export * from "./define-field";
4
5
  export * from "./define-layout";
5
6
  export * from "./define-schema";
@@ -1,10 +1,17 @@
1
1
  import { Field, FieldType, FieldTypeToValue } from "./field";
2
+ import { Entry } from "../../types/entry";
3
+ type Nullable<T> = T | null;
2
4
  type FieldValues<T extends readonly Field[]> = {
3
5
  [K in T[number]["slug"]]: Extract<T[number], {
4
6
  slug: K;
5
- }> extends {
7
+ }> extends infer FieldDef ? FieldDef extends {
8
+ type: 'reference';
9
+ is_multiple: true;
10
+ } ? Nullable<Entry[]> : FieldDef extends {
11
+ type: 'reference';
12
+ } ? Nullable<Entry> : FieldDef extends {
6
13
  type: infer Type;
7
- } ? Type extends FieldType ? FieldTypeToValue[Type] : never : never;
14
+ } ? Type extends FieldType ? FieldTypeToValue[Type] : never : never : never;
8
15
  };
9
16
  export interface BlockSchema<TFields extends readonly Field[]> {
10
17
  fields: TFields;
@@ -1 +1 @@
1
- {"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/studio/types/block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAG7D,KAAK,WAAW,CAAC,CAAC,SAAS,SAAS,KAAK,EAAE,IAAI;KAC5C,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,SAAS;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE,GAClF,IAAI,SAAS,SAAS,GACpB,gBAAgB,CAAC,IAAI,CAAC,GACtB,KAAK,GACP,KAAK;CACV,CAAC;AAEF,MAAM,WAAW,WAAW,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,WAAW,CAAC,SAAS,KAAK,EAAE,CAAC;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,WAAW,CAAC,SAAS,KAAK,EAAE,CAAC;IAChF,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC7B,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACpG;AAED,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,WAAW,CAAC,SAAS,KAAK,EAAE,CAAC,IAAI,KAAK,CAAC,aAAa,CAC7F,mBAAmB,CAAC,OAAO,CAAC,CAC7B,CAAC"}
1
+ {"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/studio/types/block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAG5B,KAAK,WAAW,CAAC,CAAC,SAAS,SAAS,KAAK,EAAE,IAAI;KAC5C,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,SAAS,MAAM,QAAQ,GAC5E,QAAQ,SAAS;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,WAAW,EAAE,IAAI,CAAA;KAAE,GACvD,QAAQ,CAAC,KAAK,EAAE,CAAC,GACjB,QAAQ,SAAS;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,GACpC,QAAQ,CAAC,KAAK,CAAC,GACf,QAAQ,SAAS;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE,GACnC,IAAI,SAAS,SAAS,GACpB,gBAAgB,CAAC,IAAI,CAAC,GACtB,KAAK,GACP,KAAK,GACX,KAAK;CACV,CAAC;AAEF,MAAM,WAAW,WAAW,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,cAAc,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,WAAW,CAAC,SAAS,KAAK,EAAE,CAAC;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvC,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,WAAW,CAAC,SAAS,KAAK,EAAE,CAAC;IAChF,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC7B,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACpG;AAED,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,WAAW,CAAC,SAAS,KAAK,EAAE,CAAC,IAAI,KAAK,CAAC,aAAa,CAC7F,mBAAmB,CAAC,OAAO,CAAC,CAC7B,CAAC"}
@@ -1,22 +1,34 @@
1
1
  import { MediaItem } from "../../types";
2
+ import { Entry } from "../../types/entry";
2
3
  type Nullable<T> = T | null;
3
4
  export type FieldTypeToValue = {
4
5
  boolean: Nullable<boolean>;
6
+ date: Nullable<string>;
7
+ datetime: Nullable<string>;
8
+ email: Nullable<string>;
5
9
  event_select: Nullable<string>;
10
+ fieldset: never;
6
11
  form_select: Nullable<string>;
7
12
  image: Nullable<MediaItem>;
8
13
  image_list: Nullable<MediaItem[]>;
14
+ json: Nullable<any>;
9
15
  list_array: Nullable<string[]>;
16
+ location: Nullable<string>;
17
+ markdown: Nullable<string>;
10
18
  media: Nullable<MediaItem>;
11
19
  menu_select: Nullable<string>;
12
20
  number: Nullable<number>;
13
21
  press_select: Nullable<string>;
22
+ reference: Nullable<Entry | Entry[]>;
14
23
  repeater: Nullable<any[]>;
15
24
  rich_text: Nullable<string>;
25
+ select: Nullable<string>;
16
26
  separator: never;
27
+ slug: Nullable<string>;
17
28
  spacer: never;
18
29
  text: Nullable<string>;
19
30
  textarea: Nullable<string>;
31
+ time: Nullable<string>;
20
32
  url: Nullable<string>;
21
33
  navigation_select: Nullable<string>;
22
34
  page_select: Nullable<string>;
@@ -32,10 +44,20 @@ export type BaseField = {
32
44
  label: string;
33
45
  value: any;
34
46
  }>;
47
+ allowed_references?: string[];
48
+ is_multiple?: boolean;
49
+ is_primary?: boolean;
50
+ show_in_list?: boolean;
51
+ order?: number;
52
+ type_id?: string | null;
35
53
  fields?: Field[];
36
54
  };
37
55
  export type Field = {
38
- [K in FieldType]: BaseField & {
56
+ [K in FieldType]: K extends 'reference' ? BaseField & {
57
+ type: K;
58
+ value?: FieldTypeToValue[K];
59
+ is_multiple?: boolean;
60
+ } : BaseField & {
39
61
  type: K;
40
62
  value?: FieldTypeToValue[K];
41
63
  };
@@ -1 +1 @@
1
- {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../src/studio/types/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B,UAAU,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IAClC,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/B,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1B,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5B,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3B,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtB,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC/B,CAAC;AACF,MAAM,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;KACjB,CAAC,IAAI,SAAS,GAAG,SAAS,GAAG;QAC5B,IAAI,EAAE,CAAC,CAAC;QACR,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;KAC7B;CACF,CAAC,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../src/studio/types/field.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,17 @@
1
1
  import { Field, FieldType, FieldTypeToValue } from "./field";
2
+ import { Entry } from "../../types/entry";
3
+ type Nullable<T> = T | null;
2
4
  type FieldValues<T extends readonly Field[]> = {
3
5
  [K in T[number]["slug"]]: Extract<T[number], {
4
6
  slug: K;
5
- }> extends {
7
+ }> extends infer FieldDef ? FieldDef extends {
8
+ type: 'reference';
9
+ is_multiple: true;
10
+ } ? Nullable<Entry[]> : FieldDef extends {
11
+ type: 'reference';
12
+ } ? Nullable<Entry> : FieldDef extends {
6
13
  type: infer Type;
7
- } ? Type extends FieldType ? FieldTypeToValue[Type] : never : never;
14
+ } ? Type extends FieldType ? FieldTypeToValue[Type] : never : never : never;
8
15
  };
9
16
  export interface LayoutSchema<TFields extends readonly Field[]> {
10
17
  fields: TFields;
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/studio/types/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAG7D,KAAK,WAAW,CAAC,CAAC,SAAS,SAAS,KAAK,EAAE,IAAI;KAC5C,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,SAAS;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE,GAClF,IAAI,SAAS,SAAS,GACpB,gBAAgB,CAAC,IAAI,CAAC,GACtB,KAAK,GACP,KAAK;CACV,CAAC;AAEF,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAC5D,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,oBAAoB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,YAAY,CAAC,SAAS,KAAK,EAAE,CAAC;IAClF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACrG"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/studio/types/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAG5B,KAAK,WAAW,CAAC,CAAC,SAAS,SAAS,KAAK,EAAE,IAAI;KAC5C,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,SAAS,MAAM,QAAQ,GAC5E,QAAQ,SAAS;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,WAAW,EAAE,IAAI,CAAA;KAAE,GACvD,QAAQ,CAAC,KAAK,EAAE,CAAC,GACjB,QAAQ,SAAS;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,GACpC,QAAQ,CAAC,KAAK,CAAC,GACf,QAAQ,SAAS;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE,GACnC,IAAI,SAAS,SAAS,GACpB,gBAAgB,CAAC,IAAI,CAAC,GACtB,KAAK,GACP,KAAK,GACX,KAAK;CACV,CAAC;AAEF,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAC5D,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,SAAS,KAAK,EAAE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,oBAAoB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,YAAY,CAAC,SAAS,KAAK,EAAE,CAAC;IAClF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACrG"}
@@ -1,10 +1,34 @@
1
+ export interface BlueprintField {
2
+ id: string;
3
+ blueprint_id: string;
4
+ name: string;
5
+ slug: string;
6
+ type: string;
7
+ type_id: string | null;
8
+ is_primary: boolean;
9
+ is_multiple: boolean;
10
+ show_in_list: boolean;
11
+ order: number;
12
+ allowed_references: string[] | null;
13
+ options: Array<{
14
+ label: string;
15
+ value: any;
16
+ }> | null;
17
+ placeholder: string | null;
18
+ created_at: string;
19
+ updated_at: string;
20
+ }
1
21
  export interface Blueprint {
2
22
  id: string;
3
23
  account_id: string;
4
24
  name: string;
5
25
  slug: string;
26
+ slug_single: string;
6
27
  description: string | null;
7
- schema: any;
28
+ is_routable: boolean;
29
+ has_location: boolean;
30
+ has_route_index: boolean;
31
+ fields: BlueprintField[];
8
32
  created_at: string;
9
33
  updated_at: string;
10
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint.d.ts","sourceRoot":"","sources":["../../src/types/blueprint.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"blueprint.d.ts","sourceRoot":"","sources":["../../src/types/blueprint.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACpC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IACrD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@antlur/backstage",
3
3
  "author": "Anthony Holmes",
4
- "version": "1.12.12",
4
+ "version": "1.12.14",
5
5
  "description": "A simple client for Backstage CMS",
6
6
  "license": "MIT",
7
7
  "repository": {
package/readme.md CHANGED
@@ -7,7 +7,8 @@ A TypeScript client library for [Backstage CMS](https://bckstg.app) with type-sa
7
7
  - 🔐 Type-safe API client for Backstage CMS
8
8
  - 🧱 Define custom blocks with full TypeScript support
9
9
  - 📐 Define custom layouts with schema validation
10
- - 🔄 CLI tools for syncing blocks and layouts
10
+ - Define custom blueprints (content types) with field schemas
11
+ - 🔄 CLI tools for syncing blocks, blueprints, and layouts
11
12
  - ⚛️ React components for page metadata and structured data
12
13
  - 🎨 Framework-agnostic design (works with Next.js, React, etc.)
13
14
 
@@ -90,11 +91,13 @@ const heroFields = [
90
91
  slug: "title",
91
92
  type: "text",
92
93
  required: true,
94
+ placeholder: "Enter hero title...",
93
95
  }),
94
96
  defineField({
95
97
  name: "Subtitle",
96
98
  slug: "subtitle",
97
- type: "text",
99
+ type: "textarea",
100
+ description: "Optional subtitle text",
98
101
  }),
99
102
  defineField({
100
103
  name: "Background Image",
@@ -102,6 +105,25 @@ const heroFields = [
102
105
  type: "image",
103
106
  required: true,
104
107
  }),
108
+ defineField({
109
+ name: "Display Style",
110
+ slug: "displayStyle",
111
+ type: "select",
112
+ options: [
113
+ { label: "Full Width", value: "full" },
114
+ { label: "Centered", value: "centered" },
115
+ { label: "Left Aligned", value: "left" },
116
+ ],
117
+ required: true,
118
+ }),
119
+ defineField({
120
+ name: "Featured Products",
121
+ slug: "featuredProducts",
122
+ type: "reference",
123
+ allowed_references: ["products"],
124
+ is_multiple: true,
125
+ description: "Select products to feature",
126
+ }),
105
127
  ] as const;
106
128
 
107
129
  export const schema = defineBlockSchema({
@@ -143,14 +165,175 @@ export const heroBlock = defineBlock({
143
165
  });
144
166
  ```
145
167
 
168
+ ## Defining Custom Blueprints
169
+
170
+ Create content types (blueprints) with custom field schemas:
171
+
172
+ ```typescript
173
+ // blueprints/customer.ts
174
+ import { defineBlueprint } from "@antlur/backstage/studio";
175
+
176
+ export const customerBlueprint = defineBlueprint({
177
+ name: "Customer",
178
+ slug: "customers",
179
+ description: "Customer testimonials and information",
180
+ fields: [
181
+ {
182
+ name: "Name",
183
+ slug: "name",
184
+ type: "text",
185
+ is_primary: true, // Primary field for display
186
+ required: true,
187
+ placeholder: "Customer full name",
188
+ },
189
+ {
190
+ name: "Email",
191
+ slug: "email",
192
+ type: "email",
193
+ required: true,
194
+ placeholder: "customer@example.com",
195
+ },
196
+ {
197
+ name: "Company",
198
+ slug: "company",
199
+ type: "text",
200
+ placeholder: "Company name",
201
+ },
202
+ {
203
+ name: "Photo",
204
+ slug: "photo",
205
+ type: "image",
206
+ },
207
+ {
208
+ name: "Testimonial",
209
+ slug: "testimonial",
210
+ type: "textarea",
211
+ required: true,
212
+ placeholder: "Customer testimonial...",
213
+ },
214
+ {
215
+ name: "Rating",
216
+ slug: "rating",
217
+ type: "select",
218
+ options: [
219
+ { label: "5 Stars", value: 5 },
220
+ { label: "4 Stars", value: 4 },
221
+ { label: "3 Stars", value: 3 },
222
+ { label: "2 Stars", value: 2 },
223
+ { label: "1 Star", value: 1 },
224
+ ],
225
+ required: true,
226
+ },
227
+ {
228
+ name: "Show in Testimonials",
229
+ slug: "showInTestimonials",
230
+ type: "boolean",
231
+ show_in_list: true, // Show in admin list view
232
+ },
233
+ ],
234
+ });
235
+ ```
236
+
237
+ Add blueprints to your config:
238
+
239
+ ```typescript
240
+ import { defineConfig } from "@antlur/backstage";
241
+ import { customerBlueprint } from "./blueprints/customer";
242
+
243
+ export default defineConfig({
244
+ accountId: process.env.BACKSTAGE_ACCOUNT_ID,
245
+ token: process.env.BACKSTAGE_API_KEY,
246
+ blueprints: [customerBlueprint],
247
+ });
248
+ ```
249
+
250
+ ## Using Reference Fields
251
+
252
+ Reference fields allow you to link to entries from specific blueprints. You can constrain which blueprints are allowed:
253
+
254
+ ```typescript
255
+ // blocks/testimonials/schema.ts
256
+ import { defineBlockSchema, defineField } from "@antlur/backstage/studio";
257
+
258
+ const testimonialFields = [
259
+ defineField({
260
+ name: "Customers",
261
+ slug: "customers",
262
+ type: "reference",
263
+ description: "Select customer entries",
264
+ allowed_references: ["customers"], // Only allow entries from the "customers" blueprint
265
+ is_multiple: true, // Allow multiple customer selections
266
+ required: true,
267
+ }),
268
+ defineField({
269
+ name: "Quote",
270
+ slug: "quote",
271
+ type: "textarea",
272
+ description: "The testimonial quote",
273
+ required: true,
274
+ }),
275
+ ];
276
+
277
+ export const schema = defineBlockSchema({
278
+ fields: testimonialFields,
279
+ });
280
+ ```
281
+
282
+ In your component, the reference field will contain the full entry data:
283
+
284
+ ```typescript
285
+ // blocks/testimonials/component.tsx
286
+ import type { BlockComponentProps } from "@antlur/backstage/studio";
287
+ import schema from "./schema";
288
+
289
+ export default function Testimonials({ block }: BlockComponentProps<typeof schema>) {
290
+ const { customers, quote } = block.fields;
291
+
292
+ return (
293
+ <div className="testimonial">
294
+ <blockquote>"{quote}"</blockquote>
295
+ <cite>
296
+ - {customers.map(customer => customer.name).join(", ")}
297
+ </cite> {/* Access entry properties */}
298
+ </div>
299
+ );
300
+ }
301
+ ```
302
+
303
+ ## Field Options
304
+
305
+ When defining fields for blocks and blueprints, you can set various options to customize their behavior:
306
+
307
+ ### Common Field Options
308
+
309
+ - `name` (required): Display name for the field
310
+ - `slug` (required): Unique identifier for the field
311
+ - `type` (required): Field type (see supported types below)
312
+ - `description`: Help text shown to content editors
313
+ - `placeholder`: Placeholder text shown in input fields
314
+ - `required`: Whether the field is required
315
+ - `options`: For select fields, array of `{ label: string, value: any }` options
316
+ - `allowed_references`: For reference fields, array of blueprint slugs to reference
317
+ - `is_multiple`: For reference fields, allow multiple selections
318
+
319
+ ### Blueprint-Specific Options
320
+
321
+ - `is_primary`: Mark as the primary field (used for display in lists)
322
+ - `show_in_list`: Show this field in admin list views
323
+ - `order`: Display order in forms (number)
324
+ - `type_id`: For fieldset references, the ID of the fieldset
325
+
146
326
  ## CLI Commands
147
327
 
148
- Sync your blocks and layouts to Backstage CMS:
328
+ Sync your blocks, blueprints, and layouts to Backstage CMS:
149
329
 
150
330
  ```bash
151
331
  # Sync blocks only
152
332
  npx backstage sync blocks
153
333
 
334
+ # Sync blueprints only
335
+ npx backstage sync blueprints
336
+
154
337
  # Sync layouts only
155
338
  npx backstage sync layouts
156
339
 
@@ -177,6 +360,7 @@ The client provides the following services:
177
360
 
178
361
  - `client.pages` - Page management
179
362
  - `client.blocks` - Block management
363
+ - `client.blueprints` - Blueprint (content type) management
180
364
  - `client.layouts` - Layout management
181
365
  - `client.locations` - Location management
182
366
  - `client.events` - Event management
@@ -190,24 +374,35 @@ The client provides the following services:
190
374
 
191
375
  ## Field Types
192
376
 
193
- Supported field types for blocks and layouts:
377
+ Supported field types for blocks, blueprints, and layouts:
194
378
 
195
379
  - `text` - Single-line text input
196
380
  - `textarea` - Multi-line text input
197
381
  - `rich_text` - Rich text editor
382
+ - `markdown` - Markdown editor
198
383
  - `number` - Numeric input
199
384
  - `boolean` - Checkbox
385
+ - `select` - Select from predefined options
386
+ - `reference` - Reference to entries from specific blueprints (supports `is_multiple` for multiple selections)
200
387
  - `url` - URL input
388
+ - `email` - Email input
389
+ - `slug` - URL slug input
390
+ - `date` - Date picker
391
+ - `time` - Time picker
392
+ - `datetime` - Date and time picker
393
+ - `location` - Location picker
201
394
  - `image` - Single image picker
202
395
  - `image_list` - Multiple image picker
203
396
  - `media` - Media item picker
204
397
  - `list_array` - Array of strings
205
398
  - `repeater` - Repeatable field group
399
+ - `fieldset` - Grouped fields
206
400
  - `event_select` - Event selector
207
401
  - `menu_select` - Menu selector
208
402
  - `form_select` - Form selector
209
403
  - `press_select` - Press release selector
210
404
  - `navigation_select` - Navigation selector
405
+ - `page_select` - Page selector
211
406
 
212
407
  ## React Components
213
408
 
@@ -0,0 +1,45 @@
1
+ import type { BackstageUserConfig } from "../../config.js";
2
+ import { BackstageClient } from "../../client.js";
3
+
4
+ export async function syncBlueprints(config: BackstageUserConfig) {
5
+ const client = new BackstageClient(config);
6
+
7
+ if (!config.blueprints || !config.blueprints.length) {
8
+ console.log("No blueprints found in config");
9
+ return;
10
+ }
11
+
12
+ const syncPromises = config.blueprints.map(async (blueprint) => {
13
+ const blueprintData = {
14
+ name: blueprint.name,
15
+ slug: blueprint.slug,
16
+ slug_single: blueprint.slug_single,
17
+ description: blueprint.description,
18
+ is_routable: blueprint.is_routable,
19
+ has_location: blueprint.has_location,
20
+ has_route_index: blueprint.has_route_index,
21
+ fields: blueprint.fields,
22
+ };
23
+
24
+ try {
25
+ await client.blueprints.create(blueprintData);
26
+ console.log(`✓ Blueprint ${blueprint.slug} created`);
27
+ } catch (err: any) {
28
+ if (err?.response?.status === 409) {
29
+ const id = err.response.data;
30
+ console.log(`⚠ Blueprint ${blueprint.slug} already exists with id ${id}. Updating...`);
31
+ try {
32
+ await client.blueprints.update(id, blueprintData);
33
+ console.log(`✓ Blueprint ${blueprint.slug} updated`);
34
+ } catch (updateErr: any) {
35
+ console.error(`✗ Failed to update blueprint ${blueprint.slug}:`, updateErr?.message || updateErr);
36
+ }
37
+ } else {
38
+ console.error(`✗ Failed to create blueprint ${blueprint.slug}:`, err?.message || err);
39
+ }
40
+ }
41
+ });
42
+
43
+ await Promise.all(syncPromises);
44
+ console.log(`\nSync complete: ${config.blueprints.length} blueprint(s) processed`);
45
+ }
package/src/cli/cli.ts CHANGED
@@ -5,6 +5,7 @@ import { resolve } from "path";
5
5
  import { program } from "commander";
6
6
  import { loadBackstageConfig } from "./load-config.js";
7
7
  import { syncBlocks } from "./actions/sync-blocks.js";
8
+ import { syncBlueprints } from "./actions/sync-blueprints.js";
8
9
  import { syncLayouts } from "./actions/sync-layouts.js";
9
10
 
10
11
  config({ path: resolve(process.cwd(), ".env") });
@@ -16,7 +17,7 @@ program
16
17
 
17
18
  program
18
19
  .command("sync <type>")
19
- .description("Sync blocks and layouts with the Backstage CMS")
20
+ .description("Sync blocks, blueprints, and layouts with the Backstage CMS")
20
21
  .action(async (type) => {
21
22
  const backstageConfig = await loadBackstageConfig();
22
23
 
@@ -30,6 +31,11 @@ program
30
31
  return;
31
32
  }
32
33
 
34
+ if (type === "blueprints") {
35
+ await syncBlueprints(backstageConfig);
36
+ return;
37
+ }
38
+
33
39
  if (type === "layouts") {
34
40
  await syncLayouts(backstageConfig);
35
41
  return;
@@ -37,11 +43,12 @@ program
37
43
 
38
44
  if (type === "all") {
39
45
  await syncBlocks(backstageConfig);
46
+ await syncBlueprints(backstageConfig);
40
47
  await syncLayouts(backstageConfig);
41
48
  return;
42
49
  }
43
50
 
44
- console.error(`Unknown type: ${type}. Valid types are: blocks, layouts, all`);
51
+ console.error(`Unknown type: ${type}. Valid types are: blocks, blueprints, layouts, all`);
45
52
  process.exit(1);
46
53
  });
47
54
 
package/src/client.ts CHANGED
@@ -2,6 +2,7 @@ import { getGlobalConfig, BackstageUserConfig } from "./config.js";
2
2
  import { AlertService } from "./endpoints/alerts.js";
3
3
  import { AuthService } from "./endpoints/auth.js";
4
4
  import { BlocksService } from "./endpoints/blocks.js";
5
+ import { BlueprintsService } from "./endpoints/blueprints.js";
5
6
  import { EntryService } from "./endpoints/entries.js";
6
7
  import { EventService } from "./endpoints/events.js";
7
8
  import { FormService } from "./endpoints/forms.js";
@@ -27,6 +28,7 @@ export class BackstageClient {
27
28
  public readonly alerts: AlertService;
28
29
  public readonly auth: AuthService;
29
30
  public readonly blocks: BlocksService;
31
+ public readonly blueprints: BlueprintsService;
30
32
  public readonly entries: EntryService;
31
33
  public readonly events: EventService;
32
34
  public readonly forms: FormService;
@@ -69,6 +71,7 @@ export class BackstageClient {
69
71
  this.alerts = new AlertService(this);
70
72
  this.auth = new AuthService(this);
71
73
  this.blocks = new BlocksService(this);
74
+ this.blueprints = new BlueprintsService(this);
72
75
  this.entries = new EntryService(this);
73
76
  this.events = new EventService(this);
74
77
  this.forms = new FormService(this);
package/src/config.ts CHANGED
@@ -2,11 +2,35 @@ import type { BlockDefinition } from "./studio/types/index.js";
2
2
 
3
3
  const DEFAULT_BASE_URL = "https://bckstg.app/api";
4
4
 
5
+ export interface BlueprintDefinition {
6
+ name: string;
7
+ slug: string;
8
+ slug_single?: string;
9
+ description?: string;
10
+ is_routable?: boolean;
11
+ has_location?: boolean;
12
+ has_route_index?: boolean;
13
+ fields: Array<{
14
+ name: string;
15
+ slug: string;
16
+ type: string;
17
+ type_id?: string | null;
18
+ is_primary?: boolean;
19
+ is_multiple?: boolean;
20
+ show_in_list?: boolean;
21
+ order: number;
22
+ allowed_references?: string[];
23
+ options?: Array<{ label: string; value: any }>;
24
+ placeholder?: string;
25
+ }>;
26
+ }
27
+
5
28
  export interface BackstageUserConfig {
6
29
  accountId?: string | undefined;
7
30
  token?: string | undefined;
8
31
  baseURL?: string;
9
32
  blocks?: BlockDefinition<any>[] | undefined;
33
+ blueprints?: BlueprintDefinition[] | undefined;
10
34
  layouts?: any[] | undefined;
11
35
  onError?: (error: Error) => void;
12
36
  }
@@ -0,0 +1,58 @@
1
+ import type { ApiCollectionResponse, ApiSingleResponse } from "../types/index";
2
+ import type { Blueprint } from "../types/blueprint";
3
+ import { BaseService } from "./base.js";
4
+
5
+ export interface CreateBlueprintParams {
6
+ name: string;
7
+ slug: string;
8
+ slug_single?: string;
9
+ description?: string;
10
+ is_routable?: boolean;
11
+ has_location?: boolean;
12
+ has_route_index?: boolean;
13
+ fields: Array<{
14
+ name: string;
15
+ slug: string;
16
+ type: string;
17
+ type_id?: string | null;
18
+ is_primary?: boolean;
19
+ is_multiple?: boolean;
20
+ show_in_list?: boolean;
21
+ order: number;
22
+ allowed_references?: string[];
23
+ options?: Array<{ label: string; value: any }>;
24
+ placeholder?: string;
25
+ }>;
26
+ }
27
+
28
+ export interface UpdateBlueprintParams extends Partial<CreateBlueprintParams> {}
29
+
30
+ export class BlueprintsService extends BaseService {
31
+ async list(options?: RequestInit): Promise<Blueprint[]> {
32
+ const { data } = await this.client.get<ApiCollectionResponse<Blueprint>>("/blueprints", options);
33
+ return data;
34
+ }
35
+
36
+ async get(id: string, options?: RequestInit): Promise<Blueprint | null> {
37
+ try {
38
+ const { data } = await this.client.get<ApiSingleResponse<Blueprint>>(`/blueprints/${id}`, options);
39
+ return data;
40
+ } catch (error) {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ async create(params: CreateBlueprintParams, options?: RequestInit): Promise<Blueprint> {
46
+ const { data } = await this.client.post<ApiSingleResponse<Blueprint>>("/blueprints", params, options);
47
+ return data;
48
+ }
49
+
50
+ async update(id: string, params: UpdateBlueprintParams, options?: RequestInit): Promise<Blueprint> {
51
+ const { data } = await this.client.put<ApiSingleResponse<Blueprint>>(`/blueprints/${id}`, params, options);
52
+ return data;
53
+ }
54
+
55
+ async delete(id: string, options?: RequestInit): Promise<void> {
56
+ await this.client.delete(`/blueprints/${id}`, options);
57
+ }
58
+ }
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ export { BackstageClient } from "./client.js";
8
8
  export * from "./endpoints/alerts.js";
9
9
  export * from "./endpoints/auth.js";
10
10
  export * from "./endpoints/blocks.js";
11
+ export * from "./endpoints/blueprints.js";
11
12
  export * from "./endpoints/entries.js";
12
13
  export * from "./endpoints/events.js";
13
14
  export * from "./endpoints/forms.js";
@@ -0,0 +1,5 @@
1
+ import type { BlueprintDefinition } from "../config.js";
2
+
3
+ export function defineBlueprint(blueprint: BlueprintDefinition): BlueprintDefinition {
4
+ return blueprint;
5
+ }
@@ -1,6 +1,7 @@
1
1
  export * from "./types";
2
2
 
3
3
  export * from "./define-block";
4
+ export * from "./define-blueprint";
4
5
  export * from "./define-field";
5
6
  export * from "./define-layout";
6
7
  export * from "./define-schema";
@@ -1,11 +1,20 @@
1
1
  import { Field, FieldType, FieldTypeToValue } from "./field";
2
+ import { Entry } from "../../types/entry";
3
+
4
+ type Nullable<T> = T | null;
2
5
 
3
6
  // Type for field values from array-based fields
4
7
  type FieldValues<T extends readonly Field[]> = {
5
- [K in T[number]["slug"]]: Extract<T[number], { slug: K }> extends { type: infer Type }
6
- ? Type extends FieldType
7
- ? FieldTypeToValue[Type]
8
- : never
8
+ [K in T[number]["slug"]]: Extract<T[number], { slug: K }> extends infer FieldDef
9
+ ? FieldDef extends { type: 'reference'; is_multiple: true }
10
+ ? Nullable<Entry[]>
11
+ : FieldDef extends { type: 'reference' }
12
+ ? Nullable<Entry>
13
+ : FieldDef extends { type: infer Type }
14
+ ? Type extends FieldType
15
+ ? FieldTypeToValue[Type]
16
+ : never
17
+ : never
9
18
  : never;
10
19
  };
11
20
 
@@ -1,24 +1,36 @@
1
1
  import { MediaItem } from "../../types";
2
+ import { Entry } from "../../types/entry";
2
3
 
3
4
  type Nullable<T> = T | null;
4
5
 
5
6
  export type FieldTypeToValue = {
6
7
  boolean: Nullable<boolean>;
8
+ date: Nullable<string>;
9
+ datetime: Nullable<string>;
10
+ email: Nullable<string>;
7
11
  event_select: Nullable<string>;
12
+ fieldset: never;
8
13
  form_select: Nullable<string>;
9
14
  image: Nullable<MediaItem>;
10
15
  image_list: Nullable<MediaItem[]>;
16
+ json: Nullable<any>;
11
17
  list_array: Nullable<string[]>;
18
+ location: Nullable<string>;
19
+ markdown: Nullable<string>;
12
20
  media: Nullable<MediaItem>;
13
21
  menu_select: Nullable<string>;
14
22
  number: Nullable<number>;
15
23
  press_select: Nullable<string>;
24
+ reference: Nullable<Entry | Entry[]>;
16
25
  repeater: Nullable<any[]>;
17
26
  rich_text: Nullable<string>;
27
+ select: Nullable<string>;
18
28
  separator: never;
29
+ slug: Nullable<string>;
19
30
  spacer: never;
20
31
  text: Nullable<string>;
21
32
  textarea: Nullable<string>;
33
+ time: Nullable<string>;
22
34
  url: Nullable<string>;
23
35
  navigation_select: Nullable<string>;
24
36
  page_select: Nullable<string>;
@@ -32,14 +44,26 @@ export type BaseField = {
32
44
  placeholder?: string;
33
45
  required?: boolean;
34
46
  options?: Array<{ label: string; value: any }>;
47
+ allowed_references?: string[];
48
+ is_multiple?: boolean;
49
+ is_primary?: boolean;
50
+ show_in_list?: boolean;
51
+ order?: number;
52
+ type_id?: string | null;
35
53
  fields?: Field[];
36
54
  };
37
55
 
38
56
  export type Field = {
39
- [K in FieldType]: BaseField & {
40
- type: K;
41
- value?: FieldTypeToValue[K];
42
- };
57
+ [K in FieldType]: K extends 'reference'
58
+ ? BaseField & {
59
+ type: K;
60
+ value?: FieldTypeToValue[K];
61
+ is_multiple?: boolean;
62
+ }
63
+ : BaseField & {
64
+ type: K;
65
+ value?: FieldTypeToValue[K];
66
+ };
43
67
  }[FieldType];
44
68
 
45
69
  // export interface Field<T extends FieldType = FieldType> {
@@ -1,11 +1,20 @@
1
1
  import { Field, FieldType, FieldTypeToValue } from "./field";
2
+ import { Entry } from "../../types/entry";
3
+
4
+ type Nullable<T> = T | null;
2
5
 
3
6
  // Type for field values from array-based fields
4
7
  type FieldValues<T extends readonly Field[]> = {
5
- [K in T[number]["slug"]]: Extract<T[number], { slug: K }> extends { type: infer Type }
6
- ? Type extends FieldType
7
- ? FieldTypeToValue[Type]
8
- : never
8
+ [K in T[number]["slug"]]: Extract<T[number], { slug: K }> extends infer FieldDef
9
+ ? FieldDef extends { type: 'reference'; is_multiple: true }
10
+ ? Nullable<Entry[]>
11
+ : FieldDef extends { type: 'reference' }
12
+ ? Nullable<Entry>
13
+ : FieldDef extends { type: infer Type }
14
+ ? Type extends FieldType
15
+ ? FieldTypeToValue[Type]
16
+ : never
17
+ : never
9
18
  : never;
10
19
  };
11
20
 
@@ -1,10 +1,32 @@
1
+ export interface BlueprintField {
2
+ id: string;
3
+ blueprint_id: string;
4
+ name: string;
5
+ slug: string;
6
+ type: string;
7
+ type_id: string | null;
8
+ is_primary: boolean;
9
+ is_multiple: boolean;
10
+ show_in_list: boolean;
11
+ order: number;
12
+ allowed_references: string[] | null;
13
+ options: Array<{ label: string; value: any }> | null;
14
+ placeholder: string | null;
15
+ created_at: string;
16
+ updated_at: string;
17
+ }
18
+
1
19
  export interface Blueprint {
2
20
  id: string;
3
21
  account_id: string;
4
22
  name: string;
5
23
  slug: string;
24
+ slug_single: string;
6
25
  description: string | null;
7
- schema: any;
26
+ is_routable: boolean;
27
+ has_location: boolean;
28
+ has_route_index: boolean;
29
+ fields: BlueprintField[];
8
30
  created_at: string;
9
31
  updated_at: string;
10
32
  }