@keragon/connector-cli 0.0.1

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 (24) hide show
  1. package/assets/index.ts +3 -0
  2. package/assets/templates/add/action/src/components/<%= componentName %>/<%= componentName %>.definition.json.ejs +113 -0
  3. package/assets/templates/add/action/src/components/<%= componentName %>/index.ts.ejs +5 -0
  4. package/assets/templates/add/implementation/connector/__tests__/<%= name %>.test.ts.ejs +28 -0
  5. package/assets/templates/add/implementation/connector/src/<%= name %>.ts.ejs +16 -0
  6. package/assets/templates/add/pollingtrigger/__tests__/<%= componentName %>.test.ts.ejs +73 -0
  7. package/assets/templates/add/pollingtrigger/src/components/<%= componentName %>/<%= componentName %>.definition.json.ejs +48 -0
  8. package/assets/templates/add/pollingtrigger/src/components/<%= componentName %>/<%= componentName %>.ts.ejs +32 -0
  9. package/assets/templates/add/pollingtrigger/src/components/<%= componentName %>/index.ts.ejs +7 -0
  10. package/assets/templates/add/trigger/__tests__/<%= componentName %>.test.ts.ejs +154 -0
  11. package/assets/templates/add/trigger/src/components/<%= componentName %>/<%= componentName %>.definition.json.ejs +42 -0
  12. package/assets/templates/add/trigger/src/components/<%= componentName %>/<%= componentName %>.ts.ejs +76 -0
  13. package/assets/templates/add/trigger/src/components/<%= componentName %>/index.ts.ejs +7 -0
  14. package/assets/templates/create/connector/README.md.ejs +1 -0
  15. package/assets/templates/create/connector/keragon.json.ejs +3 -0
  16. package/assets/templates/create/connector/package.json.ejs +18 -0
  17. package/assets/templates/create/connector/src/<%= name %>.definition.json.ejs +10 -0
  18. package/assets/templates/create/connector/src/components/index.ts.ejs +2 -0
  19. package/assets/templates/create/connector/src/index.ts.ejs +9 -0
  20. package/assets/templates/create/connector/tsconfig.json.ejs +22 -0
  21. package/assets/templates/create/connector/tsconfig.lib.json.ejs +18 -0
  22. package/assets/templates/create/connector/tsconfig.spec.json.ejs +17 -0
  23. package/main.js +2 -0
  24. package/package.json +62 -0
@@ -0,0 +1,3 @@
1
+ import path from "path";
2
+
3
+ export const assets = () => path.join(__dirname, 'assets');
@@ -0,0 +1,113 @@
1
+ <%
2
+ function formatComponentTitle(str) {
3
+ const spaced = str?.replace(/([A-Z])/g, ' $1')?.toLowerCase();
4
+ return spaced?.charAt(0).toUpperCase() + spaced?.slice(1);
5
+ }
6
+
7
+ const obj = {
8
+ id: componentId,
9
+ title: formatComponentTitle(componentName),
10
+ description: desc,
11
+ type: "action",
12
+ sdkVersion: "0.0.1"
13
+ };
14
+
15
+ if (typeof alert !== 'undefined') {
16
+ obj.alerts = [{
17
+ type: "info",
18
+ content: `More info in [article](https://go.keragon.com/${componentName})`
19
+ }];
20
+ }
21
+
22
+ if (typeof http !== 'undefined') {
23
+ obj.request = {
24
+ config: {
25
+ method: "get",
26
+ url: "/"
27
+ },
28
+ };
29
+ }
30
+
31
+ if (typeof pagination !== 'undefined') {
32
+ obj.pagination = {
33
+ strategy: pagination,
34
+ maxItems: "${ .inputs.maxItems // 250 }"
35
+ };
36
+
37
+ if (pagination === 'offset') {
38
+ Object.assign(obj.pagination, {
39
+ pageSize: 100,
40
+ setPageSize: "${ .request.params.limit = .pagination.pageSize }",
41
+ setPageToken: "${ .request.params.offset = .pagination.nextPageToken }"
42
+ });
43
+ } else if (pagination === 'page') {
44
+ Object.assign(obj.pagination, {
45
+ pageSize: 100,
46
+ setPageSize: "${ .request.params.per_page = .pagination.pageSize }",
47
+ setPageToken: "${ .request.params.page = .pagination.nextPageToken + 1 }"
48
+ });
49
+ } else if (pagination === 'cursor') {
50
+ Object.assign(obj.pagination, {
51
+ setPageToken: "${ .request.url = .pagination.nextPageToken }",
52
+ getNextPageToken: "${ .response.data.next }"
53
+ });
54
+ }
55
+ }
56
+
57
+ if (typeof errorHandler !== 'undefined') {
58
+ obj.response = {
59
+ errorHandlers: [{
60
+ condition: "${ .response.status != 200 }",
61
+ action: "throwError",
62
+ message: "${ .response.data | tostring }"
63
+ }]
64
+ };
65
+ }
66
+
67
+ if (typeof inputs !== 'undefined') {
68
+ obj.inputs = {
69
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
70
+ type: "object",
71
+ additionalProperties: false,
72
+ required: ["id"],
73
+ properties: {
74
+ id: {
75
+ type: "string",
76
+ title: "ID",
77
+ dynamicEnum: {
78
+ componentId: `${connectorId}.get`,
79
+ processInputs: "${ }",
80
+ processOutputs: "${ [.[] | {label: .name, value: .id}] }"
81
+ }
82
+ }
83
+ }
84
+ };
85
+
86
+ if (typeof pagination !== 'undefined') {
87
+ obj.inputs.properties.maxItems = {
88
+ type: "number",
89
+ title: "Max items",
90
+ default: 250
91
+ };
92
+ }
93
+ }
94
+
95
+ if (typeof outputs !== 'undefined') {
96
+ obj.outputs = {
97
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
98
+ type: "array",
99
+ title: "Items",
100
+ properties: {
101
+ id: {
102
+ type: "string",
103
+ title: "ID"
104
+ },
105
+ name: {
106
+ type: "string",
107
+ title: "Name"
108
+ }
109
+ }
110
+ };
111
+ }
112
+ %>
113
+ <%- JSON.stringify(obj, null, 2) %>
@@ -0,0 +1,5 @@
1
+ import definition from './<%= componentName %>.definition.json';
2
+
3
+ export default {
4
+ definition,
5
+ };
@@ -0,0 +1,28 @@
1
+ import {
2
+ Credentials
3
+ } from '@keragon/connector-sdk';
4
+ import app from '../src';
5
+ const { definition, ctor: <%= firstLetterUpperCase(name) %> } = app;
6
+
7
+ const setupTest = ({
8
+ credentials = {
9
+ authScheme: {
10
+ id: 'com.keragon.<%= name %>.environments.prod.authSchemes.custom',
11
+ },
12
+ }
13
+ }: {
14
+ credentials?: Credentials
15
+ }) => {
16
+ const <%= name %> = new <%= firstLetterUpperCase(name) %>({
17
+ definition, credentials,
18
+ });
19
+ return { <%= name %>, credentials }
20
+ };
21
+
22
+ describe('Connector: <%= firstLetterUpperCase(name) %> should', () => {
23
+ it('construct connector', async () => {
24
+ const { <%= name %> } = setupTest({});
25
+
26
+ expect(<%= name %>).toBeDefined();
27
+ });
28
+ });
@@ -0,0 +1,16 @@
1
+ import {
2
+ ConfigureCredentialsArgs,
3
+ <%= isHttp ? 'HttpApp' : 'App' %>,
4
+ } from '@keragon/connector-sdk';
5
+
6
+ export default class <%= firstLetterUpperCase(name) %> extends <%= isHttp ? 'HttpApp' : 'App' %> {
7
+ // TODO: default implementation
8
+ override async configureCredentials(args: ConfigureCredentialsArgs) {
9
+ const configuredCredentials = await super.configureCredentials(args);
10
+ const { authScheme } = configuredCredentials;
11
+ return {
12
+ ...configuredCredentials,
13
+ authScheme,
14
+ };
15
+ }
16
+ }
@@ -0,0 +1,73 @@
1
+ import { CloudEventData } from '@keragon/types';
2
+ import { CloudEvent } from 'cloudevents';
3
+ import app from '../src';
4
+ const { definition, ctor: <%= firstLetterUpperCase(connectorId) %> } = app;
5
+
6
+ const mockAxiosGet = jest.fn();
7
+ const mockAxiosPost = jest.fn();
8
+ const mockAxiosPut = jest.fn();
9
+ const mockAxiosDelete = jest.fn();
10
+ const mockIsAxiosError = jest.fn();
11
+ jest.mock('axios', () => ({
12
+ create: jest.fn((defaults) => ({
13
+ get: mockAxiosGet,
14
+ post: mockAxiosPost,
15
+ put: mockAxiosPut,
16
+ delete: mockAxiosDelete,
17
+ defaults,
18
+ })),
19
+ isAxiosError: jest.fn().mockImplementation(() => (mockIsAxiosError())),
20
+ }));
21
+
22
+ //Mock Date.now
23
+ const now = 1738876122999;
24
+ jest.useFakeTimers({ now });
25
+
26
+ const setUpTest = ({
27
+ store,
28
+ }: {
29
+ store?: Record<string, unknown>;
30
+ }) => {
31
+ const <%= connectorId %>: InstanceType<typeof <%= firstLetterUpperCase(connectorId) %>> = new <%= firstLetterUpperCase(connectorId) %>({
32
+ definition,
33
+ credentials: {
34
+ key: 'mockKey',
35
+ authScheme: {
36
+ // TODO authScheme
37
+ id: 'com.keragon.<%= connectorId %>.environments.prod.authSchemes.apiKey',
38
+ },
39
+ }
40
+ });
41
+
42
+ const trigger = <%= connectorId %>.constructComponent({ componentId: 'com.keragon.<%= connectorId %>.<%= componentId %>', store });
43
+ return { <%= connectorId %>, trigger, webhookUrl: 'https://test.com/v1/' };
44
+ };
45
+
46
+ describe('Component: Trigger com.keragon.<%= connectorId %>.<%= componentId %> should', () => {
47
+
48
+ it('.generateSampleEvents returns sample', async () => {
49
+ // Arrange
50
+ const { trigger } = setupTest();
51
+ const mockGetDynamicValue = jest.fn();
52
+ mockGetDynamicValue
53
+ .mockResolvedValue([
54
+ // TODO
55
+ ]);
56
+ trigger.getDynamicValue = mockGetDynamicValue;
57
+ jest.useFakeTimers({ now: 1730123456789 });
58
+
59
+ // Act
60
+ const results = await trigger.generateSampleEvents({});
61
+
62
+ // Assert
63
+ expect(mockGetDynamicValue).toHaveBeenCalledWith({
64
+ componentId: 'com.keragon.<%= connectorId %>.getItems',
65
+ processInputs: '${ {} }',
66
+ processOutputs: '${ }',
67
+ });
68
+ expect(results).toEqual([
69
+ // TODO
70
+ ]);
71
+ });
72
+
73
+ });
@@ -0,0 +1,48 @@
1
+ {
2
+ "id": "<%= componentId %>",
3
+ "title": "<%= title %>",
4
+ "description": "<%= desc %>",
5
+ "type": "trigger",
6
+ "sdkVersion": "0.0.1"
7
+ <% if (typeof alert !== 'undefined') { %>
8
+ ,"alerts": [{
9
+ "type": "info",
10
+ "content": "Due to vendor limitations you can have only one polling trigger"
11
+ }]
12
+ <% } %>,
13
+ "poll": {
14
+ "schedule": {
15
+ "cron": "*/5 * * * *"
16
+ },
17
+ "dedup": {
18
+ "strategy": "lastTimestamp",
19
+ "getDedupValue": "${ .item.created_time }"
20
+ },
21
+ "poller": {
22
+ "componentId": "<%= connectorId %>.getItems<TODO set correct component>",
23
+ "processInputs": "${ { event: .event } }",
24
+ "processOutputs": "${ . | sort_by(.created_time) | reverse }"
25
+ }
26
+ }
27
+ <% if (typeof inputs !== 'undefined') { %>
28
+ ,"inputs": {
29
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
30
+ "type": "object",
31
+ "additionalProperties": false,
32
+ "required": [
33
+ "event"
34
+ ],
35
+ "properties": {
36
+ "event": {
37
+ "type": "string",
38
+ "title": "Event",
39
+ "dynamicEnum": {
40
+ "componentId": "<%= connectorId %>.get",
41
+ "processInputs": "${ }",
42
+ "processOutputs": "${ [.[] | {label: .name, value: .type}] }"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ <% } %>
48
+ }
@@ -0,0 +1,32 @@
1
+ import {
2
+ HasSampleEvents,
3
+ SampleEvent,
4
+ PollingTrigger,
5
+ App,
6
+ } from '@keragon/connector-sdk';
7
+
8
+ export default class <%= firstLetterUpperCase(componentName) %> extends PollingTrigger<App> implements HasSampleEvents {
9
+
10
+ async generateSampleEvents({ store: _, ...inputs }: Record<string, unknown>): Promise<SampleEvent[]> {
11
+ const { a, b, c } = this.validateInputs(inputs);
12
+ const items = await this.getDynamicValue({
13
+ componentId: '<%= connectorId %>.getItems<TODO set correct component>',
14
+ processInputs: `\${ ${JSON.stringify({ a, b, c })} }`,
15
+ processOutputs: '${ sort_by(.date) | reverse }'
16
+ });
17
+ if (!Array.isArray(items)) {
18
+ throw new Error('items must be an array');
19
+ }
20
+ return items.slice(0, 5)
21
+ .map((i) => ({
22
+ label: `Sample item ${i}`,
23
+ value: {
24
+ data: {
25
+ body: i,
26
+ headers: {},
27
+ }
28
+ }
29
+ }));
30
+ }
31
+ }
32
+
@@ -0,0 +1,7 @@
1
+ import definition from './<%= componentName %>.definition.json';
2
+ import <%= firstLetterUpperCase(componentName) %> from './<%= componentName %>';
3
+
4
+ export default {
5
+ ctor: <%= firstLetterUpperCase(componentName) %>,
6
+ definition,
7
+ };
@@ -0,0 +1,154 @@
1
+ import { CloudEventData } from '@keragon/types';
2
+ import { CloudEvent } from 'cloudevents';
3
+ import app from '../src';
4
+ const { definition, ctor: <%= firstLetterUpperCase(connectorId) %> } = app;
5
+
6
+ const mockAxiosGet = jest.fn();
7
+ const mockAxiosPost = jest.fn();
8
+ const mockAxiosPut = jest.fn();
9
+ const mockAxiosDelete = jest.fn();
10
+ const mockIsAxiosError = jest.fn();
11
+ jest.mock('axios', () => ({
12
+ create: jest.fn((defaults) => ({
13
+ get: mockAxiosGet,
14
+ post: mockAxiosPost,
15
+ put: mockAxiosPut,
16
+ delete: mockAxiosDelete,
17
+ defaults,
18
+ })),
19
+ isAxiosError: jest.fn().mockImplementation(() => (mockIsAxiosError())),
20
+ }));
21
+
22
+ //Mock Date.now
23
+ const now = 1738876122999;
24
+ jest.useFakeTimers({ now });
25
+
26
+ const setUpTest = ({
27
+ store,
28
+ }: {
29
+ store?: Record<string, unknown>;
30
+ }) => {
31
+ const <%= connectorId %>: InstanceType<typeof <%= firstLetterUpperCase(connectorId) %>> = new <%= firstLetterUpperCase(connectorId) %>({
32
+ definition,
33
+ credentials: {
34
+ key: 'mockKey',
35
+ authScheme: {
36
+ // TODO authScheme
37
+ id: 'com.keragon.<%= connectorId %>.environments.prod.authSchemes.apiKey',
38
+ },
39
+ }
40
+ });
41
+
42
+ const trigger = <%= connectorId %>.constructComponent({ componentId: 'com.keragon.<%= connectorId %>.<%= componentId %>', store });
43
+ return { <%= connectorId %>, trigger, webhookUrl: 'https://test.com/v1/' };
44
+ };
45
+
46
+ describe('Component: Trigger com.keragon.<%= connectorId %>.<%= componentId %> should', () => {
47
+
48
+ describe('implement configure() and', () => {
49
+
50
+ it('register the webhook', async () => {
51
+ const { trigger, webhookUrl } = setUpTest({});
52
+
53
+ // Arrange: Mock request to register the webhook
54
+ mockAxiosPost.mockResolvedValue({ data: { data: { id: 'mockWebhookId' } } });
55
+ const inputs = {
56
+ // TODO
57
+ }
58
+
59
+ // Act
60
+ const configuredInputs = await trigger.configure(inputs, webhookUrl);
61
+
62
+ // Assert
63
+ expect(mockAxiosPost).toHaveBeenCalledWith('/', {
64
+ data: {
65
+ }
66
+ });
67
+
68
+ // Assert that the webhook id, url and secret were stored
69
+ expect(trigger.store.get('webhookURL')).toEqual('https://test.com/v2/?triggerId=com.keragon.<%= connectorId %>.<%= componentId %>');
70
+ expect(trigger.store.get('webhookID')).toEqual('mockWebhookId');
71
+
72
+ // Assert that the configured inputs are returned
73
+ expect(configuredInputs).toEqual(inputs);
74
+ });
75
+
76
+ it('deactivate an existing webhook before create a new one', async () => {
77
+ // Arrange : setup
78
+ const { trigger, webhookUrl } = setUpTest({
79
+ store: {
80
+ webhookURL: 'webhookURL',
81
+ webhookID: 'mockWebhookId1',
82
+ }
83
+ });
84
+ const inputs = {
85
+ }
86
+ // Arrange: Mock request to delete the old webhook
87
+ mockAxiosDelete.mockResolvedValue({ data: {} });
88
+ // Arrange: Mock request to create the webhook
89
+ mockAxiosPost.mockResolvedValue({ data: { data: { id: 'mockWebhookId2' } } });
90
+
91
+ // Act
92
+ await trigger.configure(inputs, webhookUrl);
93
+
94
+ // Assert
95
+ expect(mockAxiosDelete).toHaveBeenCalledWith('/webhooks/mockWebhookId1');
96
+ expect(mockAxiosPost).toHaveBeenCalledWith('/webhooks', expect.any(Object));
97
+ });
98
+
99
+ });
100
+
101
+ describe('implement run() and', () => {
102
+
103
+ it('fail if webhook request could not have data', async () => {
104
+ const { trigger } = setUpTest({
105
+ store: {}
106
+ });
107
+
108
+ const event = {} as CloudEvent<CloudEventData>;
109
+
110
+ await expect(trigger.run({ event })).rejects.toThrow('Component com.keragon.<%= connectorId %>.<%= componentId %> run() received no event payload');
111
+ });
112
+
113
+ it('return passed events', async () => {
114
+ const { trigger } = setUpTest({
115
+ store: {}
116
+ });
117
+
118
+ const mockEvent = {
119
+ }
120
+
121
+ const event = { data: { body: { events: [mockEvent] } } } as unknown as CloudEvent<CloudEventData>;
122
+
123
+ const output = await trigger.run({ event });
124
+
125
+ expect(output).toEqual({ result: [mockEvent] });
126
+ });
127
+ });
128
+
129
+ describe('implement deactivate() and', () => {
130
+
131
+ it('deletes the webhook', async () => {
132
+ const { trigger } = setUpTest({
133
+ store: {
134
+ webhookID: 'mockWebhookId',
135
+ }
136
+ });
137
+
138
+ // Arrange: Mock request to unregister the webhook
139
+ mockAxiosDelete.mockResolvedValue({});
140
+
141
+ // Act
142
+ await trigger.deactivate?.();
143
+
144
+ // Assert that the webhook was registered with the correct args
145
+ expect(mockAxiosDelete).toHaveBeenCalledWith('/webhooks/mockWebhookId');
146
+
147
+ // Assert that the store is cleared
148
+ expect(trigger.store.get('webhookURL')).toBeUndefined()
149
+ expect(trigger.store.get('webhookID')).toBeUndefined()
150
+ });
151
+
152
+ });
153
+
154
+ });
@@ -0,0 +1,42 @@
1
+ {
2
+ "id": "<%= componentId %>",
3
+ "title": "<%= title %>",
4
+ "description": "<%= desc %>",
5
+ "type": "trigger",
6
+ "sdkVersion": "0.0.1"
7
+ <% if (typeof alert !== 'undefined') { %>
8
+ ,"alerts": [{
9
+ "type": "info",
10
+ "content": "Please follow the [article](https://go.keragon.com/<%= componentName %>) to set up the trigger"
11
+ }]
12
+ <% } %>
13
+ <% if (typeof http !== 'undefined') { %>
14
+ ,"request": {
15
+ "config": {
16
+ "method": "get",
17
+ "url": "/"
18
+ }
19
+ }
20
+ <% } %>
21
+ <% if (typeof inputs !== 'undefined') { %>
22
+ ,"inputs": {
23
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
24
+ "type": "object",
25
+ "additionalProperties": false,
26
+ "required": [
27
+ "event"
28
+ ],
29
+ "properties": {
30
+ "event": {
31
+ "type": "string",
32
+ "title": "Event",
33
+ "dynamicEnum": {
34
+ "componentId": "<%= connectorId %>.get",
35
+ "processInputs": "${ }",
36
+ "processOutputs": "${ [.[] | {label: .name, value: .type}] }"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ <% } %>
42
+ }
@@ -0,0 +1,76 @@
1
+ import {
2
+ HasSampleEvents,
3
+ SampleEvent,
4
+ extractErrorMessage,
5
+ RunFunctionReturnType,
6
+ RunFunctionArgs,
7
+ <%= http ? 'HttpApp' : 'App' %>,
8
+ <%= http ? 'HttpComponent' : 'Component' %>,
9
+ } from '@keragon/connector-sdk';
10
+
11
+ const WEBHOOK_ID = 'webhookID';
12
+ const WEBHOOK_URL = 'webhookURL';
13
+
14
+ export default class <%= firstLetterUpperCase(componentName) %> extends <%- http ? 'HttpComponent<HttpApp>' : 'Component<App>' %> implements HasSampleEvents {
15
+
16
+ override async configure(inputs: Record<string, unknown> = {}, webhookURL: string, ..._rest: string[]) {
17
+ if (this.store.get(WEBHOOK_ID)) {
18
+ await this.deactivate();
19
+ }
20
+ const configuredInputs = await super.configure(inputs);
21
+ const url = new URL(webhookURL);
22
+ url.pathname = url.pathname.replace('/v1/', '/v2/');
23
+ url.searchParams.set('triggerId', this.definition.id.toLowerCase());
24
+ this.store.set(WEBHOOK_URL, url.toString());
25
+ this.store.set(WEBHOOK_URL, url.toString());
26
+
27
+ const client = await this.app.getClient();
28
+ try {
29
+ const { data: { id } } = await client.post('/', {});
30
+ this.store.set(WEBHOOK_URL, webhookURL);
31
+ this.store.set(WEBHOOK_ID, id);
32
+ return configuredInputs;
33
+ } catch (error) {
34
+ throw new Error(`Failed to configure ${this.definition.id} because ${extractErrorMessage(error)}.`);
35
+ }
36
+ }
37
+
38
+ override async run({ event }: RunFunctionArgs): Promise<RunFunctionReturnType> {
39
+ const componentId = this.definition.id;
40
+ if (!event?.data)
41
+ throw new Error(`Component ${componentId} run() received no event payload`);
42
+ const data = event.data.body;
43
+ return { result: data };
44
+ }
45
+
46
+ override async deactivate() {
47
+ try {
48
+ this.store.delete(WEBHOOK_URL);
49
+ } catch (error) {
50
+ throw new Error(`Failed to deactivate "${this.definition.id}" because ${extractErrorMessage(error)}`);
51
+ }
52
+ }
53
+
54
+ async generateSampleEvents({ store: _, ...inputs }: Record<string, unknown>): Promise<SampleEvent[]> {
55
+ const { a, b, c } = this.validateInputs(inputs);
56
+ const items = await this.getDynamicValue({
57
+ componentId: '<%= connectorId %>.getItems<TODO set correct component>',
58
+ processInputs: `\${ ${JSON.stringify({ a, b, c })} }`,
59
+ processOutputs: '${ sort_by(.date) | reverse }'
60
+ });
61
+ if (!Array.isArray(items)) {
62
+ throw new Error('items must be an array');
63
+ }
64
+ return items.slice(0, 5)
65
+ .map((i) => ({
66
+ label: `Sample item ${i}`,
67
+ value: {
68
+ data: {
69
+ body: i,
70
+ headers: {},
71
+ }
72
+ }
73
+ }));
74
+ }
75
+ }
76
+
@@ -0,0 +1,7 @@
1
+ import definition from './<%= componentName %>.definition.json';
2
+ import <%= firstLetterUpperCase(componentName) %> from './<%= componentName %>';
3
+
4
+ export default {
5
+ ctor: <%= firstLetterUpperCase(componentName) %>,
6
+ definition,
7
+ };
@@ -0,0 +1 @@
1
+ # <%= name %> connector
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "<%= name %>"
3
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@keragonhq/<%= name %>",
3
+ "version": "0.0.1",
4
+ "description": "Keragon's built-in <%= firstLetterUpperCase(name) %> app",
5
+ "main": "index.js",
6
+ "publishConfig": {
7
+ "registry": "https://npm.pkg.github.com",
8
+ "access": "restricted"
9
+ },
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "@keragon/connector-sdk": "0.0.1"
14
+ },
15
+ "devDependencies": {
16
+ "jest": "^29.7.0"
17
+ }
18
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "id": "com.keragon.<%= name %>",
3
+ "title": "<%= firstLetterUpperCase(name) %>",
4
+ "tags": <%- JSON.stringify(tags ?? []) %>,
5
+ "icon": "/assets/<%= name %>.svg",
6
+ "description": "<%= desc %>",
7
+ "version": "0.0.1",
8
+ "environments": [
9
+ ]
10
+ }
@@ -0,0 +1,2 @@
1
+ export default [
2
+ ];
@@ -0,0 +1,9 @@
1
+ import {
2
+ <%= http ? 'createHttpAppDescriptor' : 'createAppDescriptor' %>
3
+ } from '@keragon/connector-sdk';
4
+ import components from './components';
5
+ import definition from './<%= name %>.definition.json';
6
+
7
+ export default <%= http ? 'createHttpAppDescriptor' : 'createAppDescriptor' %> ({
8
+ definition: { ...definition, components },
9
+ });