@canva/cli 0.0.1-beta.2 → 0.0.1-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -106
- package/cli.js +467 -394
- package/lib/cjs/index.cjs +388 -0
- package/lib/esm/index.mjs +388 -0
- package/package.json +12 -3
- package/templates/base/backend/routers/oauth.ts +393 -0
- package/templates/base/eslint.config.mjs +2 -4
- package/templates/base/package.json +31 -25
- package/templates/base/scripts/copy_env.ts +10 -0
- package/templates/base/scripts/start/app_runner.ts +39 -2
- package/templates/base/scripts/start/context.ts +12 -6
- package/templates/base/scripts/start/start.ts +11 -0
- package/templates/base/scripts/start/tests/start.tests.ts +61 -0
- package/templates/base/utils/backend/bearer_middleware/bearer_middleware.ts +101 -0
- package/templates/base/utils/backend/bearer_middleware/index.ts +1 -0
- package/templates/base/utils/backend/bearer_middleware/tests/bearer_middleware.tests.ts +192 -0
- package/templates/base/utils/use_add_element.ts +48 -0
- package/templates/base/utils/use_feature_support.ts +28 -0
- package/templates/base/{webpack.config.cjs → webpack.config.ts} +34 -42
- package/templates/common/.gitignore.template +5 -6
- package/templates/common/.nvmrc +1 -0
- package/templates/common/.prettierrc +21 -0
- package/templates/common/.vscode/extensions.json +6 -0
- package/templates/common/README.md +4 -74
- package/templates/common/conf/eslint-local-i18n-rules/index.mjs +181 -0
- package/templates/common/conf/{eslint-general.mjs → eslint_general.mjs} +40 -0
- package/templates/common/conf/eslint_i18n.mjs +41 -0
- package/templates/common/jest.config.mjs +29 -2
- package/templates/common/jest.setup.ts +20 -0
- package/templates/common/utils/backend/base_backend/create.ts +104 -0
- package/templates/common/utils/table_wrapper.ts +477 -0
- package/templates/common/utils/tests/table_wrapper.tests.ts +252 -0
- package/templates/common/utils/use_add_element.ts +48 -0
- package/templates/common/utils/use_feature_support.ts +28 -0
- package/templates/common/utils/use_overlay_hook.ts +74 -0
- package/templates/common/utils/use_selection_hook.ts +37 -0
- package/templates/dam/backend/routers/dam.ts +17 -12
- package/templates/dam/backend/server.ts +0 -7
- package/templates/dam/eslint.config.mjs +2 -2
- package/templates/dam/package.json +51 -39
- package/templates/dam/scripts/copy_env.ts +10 -0
- package/templates/dam/scripts/start/app_runner.ts +39 -2
- package/templates/dam/scripts/start/context.ts +12 -6
- package/templates/dam/scripts/start/start.ts +11 -0
- package/templates/dam/scripts/start/tests/start.tests.ts +61 -0
- package/templates/dam/src/app.tsx +26 -138
- package/templates/dam/src/config.ts +209 -87
- package/templates/{hello_world/webpack.config.cjs → dam/webpack.config.ts} +34 -42
- package/templates/gen_ai/README.md +1 -1
- package/templates/gen_ai/backend/routers/image.ts +3 -3
- package/templates/gen_ai/backend/server.ts +0 -7
- package/templates/gen_ai/eslint.config.mjs +2 -4
- package/templates/gen_ai/package.json +56 -42
- package/templates/gen_ai/scripts/copy_env.ts +10 -0
- package/templates/gen_ai/scripts/start/app_runner.ts +39 -2
- package/templates/gen_ai/scripts/start/context.ts +12 -6
- package/templates/gen_ai/scripts/start/start.ts +11 -0
- package/templates/gen_ai/scripts/start/tests/start.tests.ts +61 -0
- package/templates/gen_ai/src/api/api.ts +1 -39
- package/templates/gen_ai/src/app.tsx +16 -10
- package/templates/gen_ai/src/components/footer.messages.ts +0 -5
- package/templates/gen_ai/src/components/footer.tsx +2 -16
- package/templates/gen_ai/src/components/image_grid.tsx +8 -6
- package/templates/gen_ai/src/components/index.ts +0 -1
- package/templates/gen_ai/src/components/tests/remaining_credit.tests.tsx +43 -0
- package/templates/gen_ai/src/context/app_context.tsx +4 -26
- package/templates/gen_ai/src/context/context.messages.ts +1 -12
- package/templates/gen_ai/src/home.tsx +13 -0
- package/templates/gen_ai/src/index.tsx +2 -18
- package/templates/gen_ai/src/routes/routes.tsx +2 -2
- package/templates/gen_ai/utils/backend/bearer_middleware/bearer_middleware.ts +101 -0
- package/templates/gen_ai/utils/backend/bearer_middleware/index.ts +1 -0
- package/templates/gen_ai/utils/backend/bearer_middleware/tests/bearer_middleware.tests.ts +192 -0
- package/templates/gen_ai/{webpack.config.cjs → webpack.config.ts} +34 -42
- package/templates/hello_world/eslint.config.mjs +2 -4
- package/templates/hello_world/package.json +55 -33
- package/templates/hello_world/scripts/copy_env.ts +10 -0
- package/templates/hello_world/scripts/start/app_runner.ts +39 -2
- package/templates/hello_world/scripts/start/context.ts +12 -6
- package/templates/hello_world/scripts/start/start.ts +11 -0
- package/templates/hello_world/scripts/start/tests/start.tests.ts +61 -0
- package/templates/hello_world/src/app.tsx +24 -2
- package/templates/hello_world/src/tests/__snapshots__/app.tests.tsx.snap +45 -0
- package/templates/hello_world/src/tests/app.tests.tsx +86 -0
- package/templates/hello_world/utils/use_add_element.ts +48 -0
- package/templates/hello_world/utils/use_feature_support.ts +28 -0
- package/templates/{dam/webpack.config.cjs → hello_world/webpack.config.ts} +34 -42
- package/templates/common/conf/eslint-i18n.mjs +0 -23
- package/templates/dam/backend/database/database.ts +0 -42
- package/templates/dam/backend/routers/auth.ts +0 -285
- package/templates/gen_ai/backend/routers/auth.ts +0 -285
- package/templates/gen_ai/src/components/logged_in_status.tsx +0 -44
- package/templates/gen_ai/src/services/auth.tsx +0 -31
- package/templates/gen_ai/src/services/index.ts +0 -1
- /package/templates/{gen_ai → common}/utils/backend/jwt_middleware/index.ts +0 -0
- /package/templates/{gen_ai → common}/utils/backend/jwt_middleware/jwt_middleware.ts +0 -0
- /package/templates/{gen_ai → common}/utils/backend/jwt_middleware/tests/jwt_middleware.tests.ts +0 -0
|
@@ -1,95 +1,217 @@
|
|
|
1
1
|
import type { Config } from "@canva/app-components";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
2
3
|
|
|
3
4
|
type ContainerTypes = "folder";
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
5
|
+
export const useConfig = (): Config<ContainerTypes> => {
|
|
6
|
+
const intl = useIntl();
|
|
7
|
+
return {
|
|
8
|
+
serviceName: intl.formatMessage({
|
|
9
|
+
defaultMessage: "Example App",
|
|
10
|
+
description:
|
|
11
|
+
"Name of the service where the app will pull digital assets from",
|
|
12
|
+
}),
|
|
13
|
+
search: {
|
|
14
|
+
enabled: true,
|
|
15
|
+
filterFormConfig: {
|
|
16
|
+
containerTypes: ["folder"],
|
|
17
|
+
filters: [
|
|
18
|
+
{
|
|
19
|
+
filterType: "CHECKBOX",
|
|
20
|
+
label: intl.formatMessage({
|
|
21
|
+
defaultMessage: "File Type",
|
|
22
|
+
description: "Label of filters for file type",
|
|
23
|
+
}),
|
|
24
|
+
key: "fileType",
|
|
25
|
+
options: [
|
|
26
|
+
{ value: "mp4", label: "MP4" },
|
|
27
|
+
{ value: "png", label: "PNG" },
|
|
28
|
+
{ value: "jpeg", label: "JPEG" },
|
|
29
|
+
],
|
|
30
|
+
allowCustomValue: true,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
filterType: "RADIO",
|
|
34
|
+
label: intl.formatMessage({
|
|
35
|
+
defaultMessage: "Size",
|
|
36
|
+
description: "Label of filters for asset size",
|
|
37
|
+
}),
|
|
38
|
+
key: "size",
|
|
39
|
+
options: [
|
|
40
|
+
{
|
|
41
|
+
label: intl.formatMessage({
|
|
42
|
+
defaultMessage: "Large (800+ px)",
|
|
43
|
+
description: "One of the filter options for asset size",
|
|
44
|
+
}),
|
|
45
|
+
value: "large",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: intl.formatMessage({
|
|
49
|
+
defaultMessage: "Medium (200-799px)",
|
|
50
|
+
description: "One of the filter options for asset size",
|
|
51
|
+
}),
|
|
52
|
+
value: "medium",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
allowCustomValue: true,
|
|
56
|
+
customValueInputType: "SIZE_RANGE",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
filterType: "RADIO",
|
|
60
|
+
label: intl.formatMessage({
|
|
61
|
+
defaultMessage: "Update Date",
|
|
62
|
+
description: "Label of the filters for asset's update date",
|
|
63
|
+
}),
|
|
64
|
+
key: "updateDate",
|
|
65
|
+
options: [
|
|
66
|
+
{
|
|
67
|
+
value: ">now-30m",
|
|
68
|
+
label: intl.formatMessage({
|
|
69
|
+
defaultMessage: "Last 30 Minutes",
|
|
70
|
+
description:
|
|
71
|
+
"One of the filter options for asset update date",
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
value: ">now-7d",
|
|
76
|
+
label: intl.formatMessage({
|
|
77
|
+
defaultMessage: "Last 7 days",
|
|
78
|
+
description:
|
|
79
|
+
"One of the filter options for asset update date",
|
|
80
|
+
}),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
allowCustomValue: true,
|
|
84
|
+
customValueInputType: "DATE_RANGE",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
filterType: "RADIO",
|
|
88
|
+
label: intl.formatMessage({
|
|
89
|
+
defaultMessage: "Design Status",
|
|
90
|
+
description: "Label of the filters for asset's design status",
|
|
91
|
+
}),
|
|
92
|
+
key: "designStatus",
|
|
93
|
+
options: [
|
|
94
|
+
{
|
|
95
|
+
value: "approved",
|
|
96
|
+
label: intl.formatMessage({
|
|
97
|
+
defaultMessage: "Approved",
|
|
98
|
+
description:
|
|
99
|
+
"One of the filter options for asset design status",
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
value: "rejected",
|
|
104
|
+
label: intl.formatMessage({
|
|
105
|
+
defaultMessage: "Rejected",
|
|
106
|
+
description:
|
|
107
|
+
"One of the filter options for asset design status",
|
|
108
|
+
}),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
value: "draft",
|
|
112
|
+
label: intl.formatMessage({
|
|
113
|
+
defaultMessage: "Draft",
|
|
114
|
+
description:
|
|
115
|
+
"One of the filter options for asset design status",
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
allowCustomValue: true,
|
|
120
|
+
customValueInputType: "PLAIN_TEXT",
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
63
124
|
},
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
surface: "
|
|
73
|
-
|
|
125
|
+
containerTypes: [
|
|
126
|
+
{
|
|
127
|
+
value: "folder",
|
|
128
|
+
label: intl.formatMessage({
|
|
129
|
+
defaultMessage: "Folders",
|
|
130
|
+
description: "Name of the asset container type",
|
|
131
|
+
}),
|
|
132
|
+
listingSurfaces: [
|
|
133
|
+
{ surface: "HOMEPAGE" },
|
|
134
|
+
{
|
|
135
|
+
surface: "CONTAINER",
|
|
136
|
+
parentContainerTypes: ["folder"],
|
|
137
|
+
},
|
|
138
|
+
{ surface: "SEARCH" },
|
|
139
|
+
],
|
|
140
|
+
searchInsideContainer: {
|
|
141
|
+
enabled: true,
|
|
142
|
+
placeholder: intl.formatMessage({
|
|
143
|
+
defaultMessage: "Search for media inside this folder",
|
|
144
|
+
description: "Placeholder of a search input box",
|
|
145
|
+
}),
|
|
74
146
|
},
|
|
75
|
-
{ surface: "SEARCH" },
|
|
76
|
-
],
|
|
77
|
-
searchInsideContainer: {
|
|
78
|
-
enabled: true,
|
|
79
|
-
placeholder: "Search for resources inside this folder",
|
|
80
147
|
},
|
|
148
|
+
],
|
|
149
|
+
sortOptions: [
|
|
150
|
+
{
|
|
151
|
+
value: "created_at DESC",
|
|
152
|
+
label: intl.formatMessage({
|
|
153
|
+
defaultMessage: "Creation date (newest)",
|
|
154
|
+
description: "One of the sort options",
|
|
155
|
+
}),
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
value: "created_at ASC",
|
|
159
|
+
label: intl.formatMessage({
|
|
160
|
+
defaultMessage: "Creation date (oldest)",
|
|
161
|
+
description: "One of the sort options",
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
value: "updated_at DESC",
|
|
166
|
+
label: intl.formatMessage({
|
|
167
|
+
defaultMessage: "Updated (newest)",
|
|
168
|
+
description: "One of the sort options",
|
|
169
|
+
}),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
value: "updated_at ASC",
|
|
173
|
+
label: intl.formatMessage({
|
|
174
|
+
defaultMessage: "Updated (oldest)",
|
|
175
|
+
description: "One of the sort options",
|
|
176
|
+
}),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
value: "name ASC",
|
|
180
|
+
label: intl.formatMessage({
|
|
181
|
+
defaultMessage: "Name (A-Z)",
|
|
182
|
+
description: "One of the sort options",
|
|
183
|
+
}),
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
value: "name DESC",
|
|
187
|
+
label: intl.formatMessage({
|
|
188
|
+
defaultMessage: "Name (Z-A)",
|
|
189
|
+
description: "One of the sort options",
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
layouts: ["MASONRY", "LIST"],
|
|
194
|
+
resourceTypes: ["IMAGE", "VIDEO", "EMBED"],
|
|
195
|
+
moreInfoMessage: intl.formatMessage({
|
|
196
|
+
defaultMessage:
|
|
197
|
+
"At the moment, we only support images and videos. Corrupted and unsupported files will not appear.",
|
|
198
|
+
description: "Helper text to explain why some assets are not visible",
|
|
199
|
+
}),
|
|
200
|
+
// TODO remove `export` if your app does not support exporting the Canva design into an external platform
|
|
201
|
+
export: {
|
|
202
|
+
enabled: true,
|
|
203
|
+
// TODO provide a container type that user can choose to save into, or remove this field if user doesn't need to choose a container
|
|
204
|
+
containerTypes: ["folder"],
|
|
205
|
+
// TODO remove file types that are not supported by your platform
|
|
206
|
+
acceptedFileTypes: [
|
|
207
|
+
"png",
|
|
208
|
+
"pdf_standard",
|
|
209
|
+
"jpg",
|
|
210
|
+
"gif",
|
|
211
|
+
"svg",
|
|
212
|
+
"video",
|
|
213
|
+
"pptx",
|
|
214
|
+
],
|
|
81
215
|
},
|
|
82
|
-
|
|
83
|
-
sortOptions: [
|
|
84
|
-
{ value: "created_at DESC", label: "Creation date (newest)" },
|
|
85
|
-
{ value: "created_at ASC", label: "Creation date (oldest)" },
|
|
86
|
-
{ value: "updated_at DESC", label: "Updated (newest)" },
|
|
87
|
-
{ value: "updated_at ASC", label: "Updated (oldest)" },
|
|
88
|
-
{ value: "name ASC", label: "Name (A-Z)" },
|
|
89
|
-
{ value: "name DESC", label: "Name (Z-A)" },
|
|
90
|
-
],
|
|
91
|
-
layouts: ["MASONRY", "LIST"],
|
|
92
|
-
resourceTypes: ["IMAGE", "VIDEO", "EMBED"],
|
|
93
|
-
moreInfoMessage:
|
|
94
|
-
"At the moment, we only support images and videos. Corrupted and unsupported files will not appear.",
|
|
216
|
+
};
|
|
95
217
|
};
|
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { Configuration } from "webpack";
|
|
2
|
+
import { DefinePlugin, optimize } from "webpack";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as TerserPlugin from "terser-webpack-plugin";
|
|
5
|
+
import { transform } from "@formatjs/ts-transformer";
|
|
6
|
+
import * as chalk from "chalk";
|
|
7
|
+
import { config } from "dotenv";
|
|
8
|
+
import { Configuration as DevServerConfiguration } from "webpack-dev-server";
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* @returns {Object}
|
|
22
|
-
*/
|
|
23
|
-
function buildConfig({
|
|
10
|
+
config();
|
|
11
|
+
|
|
12
|
+
type DevConfig = {
|
|
13
|
+
port: number;
|
|
14
|
+
enableHmr: boolean;
|
|
15
|
+
enableHttps: boolean;
|
|
16
|
+
appOrigin?: string;
|
|
17
|
+
appId?: string; // Deprecated in favour of appOrigin
|
|
18
|
+
certFile?: string;
|
|
19
|
+
keyFile?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function buildConfig({
|
|
24
23
|
devConfig,
|
|
25
24
|
appEntry = path.join(process.cwd(), "src", "index.tsx"),
|
|
26
25
|
backendHost = process.env.CANVA_BACKEND_HOST,
|
|
27
|
-
}
|
|
26
|
+
}: {
|
|
27
|
+
devConfig?: DevConfig;
|
|
28
|
+
appEntry?: string;
|
|
29
|
+
backendHost?: string;
|
|
30
|
+
} = {}): Configuration & DevServerConfiguration {
|
|
28
31
|
const mode = devConfig ? "development" : "production";
|
|
29
32
|
|
|
30
33
|
if (!backendHost) {
|
|
@@ -173,32 +176,23 @@ function buildConfig({
|
|
|
173
176
|
}),
|
|
174
177
|
// Apps can only submit a single JS file via the developer portal
|
|
175
178
|
new optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
|
176
|
-
],
|
|
179
|
+
].filter(Boolean),
|
|
177
180
|
...buildDevConfig(devConfig),
|
|
178
181
|
};
|
|
179
182
|
}
|
|
180
183
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
* @param {boolean} [options.enableHmr]
|
|
186
|
-
* @param {boolean} [options.enableHttps]
|
|
187
|
-
* @param {string} [options.appOrigin]
|
|
188
|
-
* @param {string} [options.appId] - Deprecated in favour of appOrigin
|
|
189
|
-
* @param {string} [options.certFile]
|
|
190
|
-
* @param {string} [options.keyFile]
|
|
191
|
-
* @returns {Object|null}
|
|
192
|
-
*/
|
|
193
|
-
function buildDevConfig(options) {
|
|
184
|
+
function buildDevConfig(options?: DevConfig): {
|
|
185
|
+
devtool?: string;
|
|
186
|
+
devServer?: DevServerConfiguration;
|
|
187
|
+
} {
|
|
194
188
|
if (!options) {
|
|
195
|
-
return
|
|
189
|
+
return {};
|
|
196
190
|
}
|
|
197
191
|
|
|
198
192
|
const { port, enableHmr, appOrigin, appId, enableHttps, certFile, keyFile } =
|
|
199
193
|
options;
|
|
200
194
|
|
|
201
|
-
let devServer = {
|
|
195
|
+
let devServer: DevServerConfiguration = {
|
|
202
196
|
server: enableHttps
|
|
203
197
|
? {
|
|
204
198
|
type: "https",
|
|
@@ -265,6 +259,4 @@ function buildDevConfig(options) {
|
|
|
265
259
|
};
|
|
266
260
|
}
|
|
267
261
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
module.exports.buildConfig = buildConfig;
|
|
262
|
+
export default buildConfig;
|
|
@@ -20,7 +20,7 @@ In this template, we've included a basic obscenity filter to stop users from cre
|
|
|
20
20
|
|
|
21
21
|
### Backend
|
|
22
22
|
|
|
23
|
-
This template includes a simple Express server as a sample backend. Please note that this server is not production-ready, and we advise using it solely for instructional purposes to demonstrate API calls.
|
|
23
|
+
This template includes a simple Express server as a sample backend. Please note that this server is not production-ready, and we advise using it solely for instructional purposes to demonstrate API calls. If you require authentication for your app, we recommend looking at the authentication example provided in the [starter kit](https://github.com/canva-sdks/canva-apps-sdk-starter-kit).
|
|
24
24
|
|
|
25
25
|
### Thumbnails
|
|
26
26
|
|
|
@@ -93,7 +93,7 @@ export const createImageRouter = () => {
|
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
95
|
* GET endpoint to retrieve user credits.
|
|
96
|
-
*
|
|
96
|
+
* Returns the current number of credits available to the user.
|
|
97
97
|
*/
|
|
98
98
|
router.get(Routes.CREDITS, async (req, res) => {
|
|
99
99
|
res.status(200).send({
|
|
@@ -103,7 +103,7 @@ export const createImageRouter = () => {
|
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* POST endpoint to purchase credits.
|
|
106
|
-
*
|
|
106
|
+
* Increments the user's credits by the number of credits in a bundle.
|
|
107
107
|
* This endpoint should be backed by proper input validation to prevent misuse.
|
|
108
108
|
*/
|
|
109
109
|
router.post(Routes.PURCHASE_CREDITS, async (req, res) => {
|
|
@@ -115,7 +115,7 @@ export const createImageRouter = () => {
|
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
* GET endpoint to generate images based on a prompt.
|
|
118
|
-
*
|
|
118
|
+
* Generates images based on the provided prompt and adds a job to the processing queue.
|
|
119
119
|
* If there are not enough credits, it returns a 403 error.
|
|
120
120
|
* If the prompt parameter is missing, it returns a 400 error.
|
|
121
121
|
* Once the job is added to the queue, it returns a jobId that can be used to check the job status.
|
|
@@ -2,7 +2,6 @@ import * as express from "express";
|
|
|
2
2
|
import * as cors from "cors";
|
|
3
3
|
import { createBaseServer } from "../utils/backend/base_backend/create";
|
|
4
4
|
import { createImageRouter } from "./routers/image";
|
|
5
|
-
import { createAuthRouter } from "./routers/auth";
|
|
6
5
|
|
|
7
6
|
async function main() {
|
|
8
7
|
const router = express.Router();
|
|
@@ -37,12 +36,6 @@ async function main() {
|
|
|
37
36
|
*/
|
|
38
37
|
router.use(cors());
|
|
39
38
|
|
|
40
|
-
/**
|
|
41
|
-
* Add routes for authorisation.
|
|
42
|
-
*/
|
|
43
|
-
const authRouter = createAuthRouter();
|
|
44
|
-
router.use(authRouter);
|
|
45
|
-
|
|
46
39
|
/**
|
|
47
40
|
* Add routes for image generation.
|
|
48
41
|
*/
|
|
@@ -2,8 +2,8 @@ import path from "node:path";
|
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import js from "@eslint/js";
|
|
4
4
|
import { FlatCompat } from "@eslint/eslintrc";
|
|
5
|
-
import general from "./conf/
|
|
6
|
-
import i18n from "./conf/
|
|
5
|
+
import general from "./conf/eslint_general.mjs";
|
|
6
|
+
import i18n from "./conf/eslint_i18n.mjs";
|
|
7
7
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
@@ -20,8 +20,6 @@ export default [
|
|
|
20
20
|
"**/dist",
|
|
21
21
|
"**/*.d.ts",
|
|
22
22
|
"**/*.d.tsx",
|
|
23
|
-
"**/sdk",
|
|
24
|
-
"**/internal",
|
|
25
23
|
"**/*.config.*",
|
|
26
24
|
],
|
|
27
25
|
},
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"name": "gen_ai",
|
|
4
4
|
"description": "An example app demonstrating common patterns that you might use in a generative AI app.",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"extract": "formatjs extract
|
|
7
|
-
"build": "webpack --config webpack.config.
|
|
6
|
+
"extract": "formatjs extract \"src/**/*.{ts,tsx}\" --out-file dist/messages_en.json",
|
|
7
|
+
"build": "webpack --config webpack.config.ts --mode production && npm run extract",
|
|
8
8
|
"format": "prettier '**/*.{css,ts,tsx}' --no-config --write",
|
|
9
9
|
"format:check": "prettier '**/*.{css,ts,tsx}' --no-config --check --ignore-path",
|
|
10
10
|
"format:file": "prettier $1 --no-config --write",
|
|
@@ -12,82 +12,96 @@
|
|
|
12
12
|
"lint:fix": "eslint . --fix",
|
|
13
13
|
"lint:types": "tsc",
|
|
14
14
|
"start": "ts-node ./scripts/start/start.ts",
|
|
15
|
+
"start:preview": "npm run start -- --preview",
|
|
15
16
|
"test": "jest --no-cache",
|
|
16
|
-
"test:watch": "jest --watchAll"
|
|
17
|
+
"test:watch": "jest --watchAll",
|
|
18
|
+
"postinstall": "ts-node ./scripts/copy_env.ts"
|
|
17
19
|
},
|
|
18
20
|
"dependencies": {
|
|
19
|
-
"@canva/app-i18n-kit": "^
|
|
20
|
-
"@canva/app-ui-kit": "^
|
|
21
|
-
"@canva/asset": "^1.
|
|
22
|
-
"@canva/design": "^
|
|
23
|
-
"@canva/
|
|
24
|
-
"@canva/
|
|
25
|
-
"
|
|
21
|
+
"@canva/app-i18n-kit": "^1.0.2",
|
|
22
|
+
"@canva/app-ui-kit": "^4.8.0",
|
|
23
|
+
"@canva/asset": "^2.1.0",
|
|
24
|
+
"@canva/design": "^2.4.0",
|
|
25
|
+
"@canva/error": "^2.1.0",
|
|
26
|
+
"@canva/platform": "^2.1.0",
|
|
27
|
+
"@canva/user": "^2.1.0",
|
|
28
|
+
"cookie-parser": "1.4.7",
|
|
26
29
|
"cors": "2.8.5",
|
|
27
|
-
"html-react-parser": "5.
|
|
28
|
-
"obscenity": "0.4.
|
|
30
|
+
"html-react-parser": "5.2.2",
|
|
31
|
+
"obscenity": "0.4.1",
|
|
29
32
|
"react": "18.3.1",
|
|
30
33
|
"react-dom": "18.3.1",
|
|
31
|
-
"react-error-boundary": "4.
|
|
32
|
-
"react-intl": "6.
|
|
33
|
-
"react-router-dom": "6.
|
|
34
|
+
"react-error-boundary": "4.1.2",
|
|
35
|
+
"react-intl": "6.8.7",
|
|
36
|
+
"react-router-dom": "6.28.0"
|
|
34
37
|
},
|
|
35
38
|
"devDependencies": {
|
|
36
|
-
"@
|
|
37
|
-
"@eslint/
|
|
38
|
-
"@
|
|
39
|
-
"@formatjs/
|
|
39
|
+
"@canva/cli": ">= 0.0.1-beta.13 < 0.0.2",
|
|
40
|
+
"@eslint/eslintrc": "3.2.0",
|
|
41
|
+
"@eslint/js": "9.18.0",
|
|
42
|
+
"@formatjs/cli": "6.3.15",
|
|
43
|
+
"@formatjs/ts-transformer": "3.13.27",
|
|
40
44
|
"@ngrok/ngrok": "1.4.1",
|
|
45
|
+
"@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
|
|
41
46
|
"@svgr/webpack": "8.1.0",
|
|
47
|
+
"@testing-library/react": "16.1.0",
|
|
42
48
|
"@types/debug": "4.1.12",
|
|
43
49
|
"@types/express": "4.17.21",
|
|
44
|
-
"@types/express-serve-static-core": "4.19.
|
|
45
|
-
"@types/jest": "29.5.
|
|
46
|
-
"@types/jsonwebtoken": "9.0.
|
|
50
|
+
"@types/express-serve-static-core": "4.19.6",
|
|
51
|
+
"@types/jest": "29.5.14",
|
|
52
|
+
"@types/jsonwebtoken": "9.0.7",
|
|
47
53
|
"@types/node": "20.10.0",
|
|
48
|
-
"@types/node-fetch": "2.6.
|
|
54
|
+
"@types/node-fetch": "2.6.12",
|
|
49
55
|
"@types/node-forge": "1.3.11",
|
|
50
56
|
"@types/nodemon": "1.19.6",
|
|
51
57
|
"@types/prompts": "2.4.9",
|
|
52
|
-
"@types/react": "18.3.
|
|
53
|
-
"@types/react-dom": "18.3.
|
|
58
|
+
"@types/react": "18.3.12",
|
|
59
|
+
"@types/react-dom": "18.3.1",
|
|
60
|
+
"@types/webpack": "5.28.5",
|
|
61
|
+
"@types/webpack-dev-server": "4.7.1",
|
|
54
62
|
"@types/webpack-env": "1.18.5",
|
|
55
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
56
|
-
"@typescript-eslint/parser": "8.
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "8.20.0",
|
|
64
|
+
"@typescript-eslint/parser": "8.20.0",
|
|
57
65
|
"chalk": "4.1.2",
|
|
58
66
|
"cli-table3": "0.6.5",
|
|
59
67
|
"css-loader": "7.1.2",
|
|
60
68
|
"css-modules-typescript-loader": "4.0.1",
|
|
61
|
-
"cssnano": "7.0.
|
|
62
|
-
"debug": "4.
|
|
63
|
-
"dotenv": "16.4.
|
|
64
|
-
"eslint": "
|
|
65
|
-
"eslint-plugin-formatjs": "
|
|
66
|
-
"eslint-plugin-jest": "28.
|
|
67
|
-
"eslint-plugin-react": "7.
|
|
69
|
+
"cssnano": "7.0.6",
|
|
70
|
+
"debug": "4.4.0",
|
|
71
|
+
"dotenv": "16.4.7",
|
|
72
|
+
"eslint": "9.18.0",
|
|
73
|
+
"eslint-plugin-formatjs": "5.2.8",
|
|
74
|
+
"eslint-plugin-jest": "28.11.0",
|
|
75
|
+
"eslint-plugin-react": "7.37.4",
|
|
76
|
+
"eslint-plugin-unicorn": "56.0.1",
|
|
68
77
|
"exponential-backoff": "3.1.1",
|
|
69
|
-
"express": "4.
|
|
78
|
+
"express": "4.21.2",
|
|
70
79
|
"express-basic-auth": "1.2.1",
|
|
71
80
|
"jest": "29.7.0",
|
|
81
|
+
"jest-css-modules-transform": "4.4.2",
|
|
82
|
+
"jest-environment-jsdom": "29.7.0",
|
|
72
83
|
"jsonwebtoken": "9.0.2",
|
|
73
84
|
"jwks-rsa": "3.1.0",
|
|
74
|
-
"mini-css-extract-plugin": "2.9.
|
|
85
|
+
"mini-css-extract-plugin": "2.9.2",
|
|
75
86
|
"node-fetch": "3.3.2",
|
|
76
87
|
"node-forge": "1.3.1",
|
|
77
88
|
"nodemon": "3.0.1",
|
|
89
|
+
"open": "8.4.2",
|
|
78
90
|
"postcss-loader": "8.1.1",
|
|
79
|
-
"prettier": "3.
|
|
91
|
+
"prettier": "3.4.2",
|
|
80
92
|
"prompts": "2.4.2",
|
|
93
|
+
"react-refresh": "0.16.0",
|
|
81
94
|
"style-loader": "4.0.0",
|
|
82
|
-
"terser-webpack-plugin": "5.3.
|
|
83
|
-
"
|
|
84
|
-
"ts-
|
|
95
|
+
"terser-webpack-plugin": "5.3.11",
|
|
96
|
+
"tree-kill": "1.2.2",
|
|
97
|
+
"ts-jest": "29.2.5",
|
|
98
|
+
"ts-loader": "9.5.2",
|
|
85
99
|
"ts-node": "10.9.2",
|
|
86
100
|
"typescript": "5.5.4",
|
|
87
101
|
"url-loader": "4.1.1",
|
|
88
|
-
"webpack": "5.
|
|
102
|
+
"webpack": "5.97.1",
|
|
89
103
|
"webpack-cli": "5.1.4",
|
|
90
|
-
"webpack-dev-server": "5.0
|
|
104
|
+
"webpack-dev-server": "5.2.0",
|
|
91
105
|
"yargs": "17.7.2"
|
|
92
106
|
}
|
|
93
107
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
|
|
5
|
+
const envPath = path.resolve(__dirname, "..", ".env");
|
|
6
|
+
const templatePath = path.resolve(__dirname, "..", ".env.template");
|
|
7
|
+
|
|
8
|
+
if (!fs.existsSync(envPath)) {
|
|
9
|
+
fs.copyFileSync(templatePath, envPath);
|
|
10
|
+
}
|