@canva/cli 1.19.0 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +1 -9
- package/cli.js +408 -409
- package/package.json +1 -2
- package/templates/base/backend/base_backend/create.ts +0 -114
- package/templates/base/backend/database/database.ts +0 -42
- package/templates/base/backend/routers/auth.ts +0 -288
- package/templates/base/declarations/declarations.d.ts +0 -29
- package/templates/base/eslint.config.mjs +0 -14
- package/templates/base/package.json +0 -91
- package/templates/base/scripts/copy_env.ts +0 -13
- package/templates/base/scripts/ssl/ssl.ts +0 -131
- package/templates/base/scripts/start/app_runner.ts +0 -223
- package/templates/base/scripts/start/context.ts +0 -171
- package/templates/base/scripts/start/start.ts +0 -46
- package/templates/base/scripts/start.tests.ts +0 -61
- package/templates/base/styles/components.css +0 -38
- package/templates/base/tsconfig.json +0 -56
- package/templates/base/webpack.config.ts +0 -247
- package/templates/common/.env.template +0 -6
- package/templates/common/.gitignore.template +0 -8
- package/templates/common/.nvmrc +0 -1
- package/templates/common/.prettierrc +0 -21
- package/templates/common/LICENSE.md +0 -48
- package/templates/common/README.md +0 -179
- package/templates/common/jest.config.mjs +0 -35
- package/templates/common/jest.setup.ts +0 -35
- package/templates/content_publisher/README.md +0 -58
- package/templates/content_publisher/canva-app.json +0 -17
- package/templates/content_publisher/declarations/declarations.d.ts +0 -29
- package/templates/content_publisher/eslint.config.mjs +0 -14
- package/templates/content_publisher/package.json +0 -90
- package/templates/content_publisher/scripts/copy_env.ts +0 -13
- package/templates/content_publisher/scripts/ssl/ssl.ts +0 -131
- package/templates/content_publisher/scripts/start/app_runner.ts +0 -223
- package/templates/content_publisher/scripts/start/context.ts +0 -171
- package/templates/content_publisher/scripts/start/start.ts +0 -46
- package/templates/content_publisher/src/index.tsx +0 -4
- package/templates/content_publisher/src/intents/content_publisher/index.tsx +0 -107
- package/templates/content_publisher/src/intents/content_publisher/post_preview.tsx +0 -240
- package/templates/content_publisher/src/intents/content_publisher/preview_ui.tsx +0 -62
- package/templates/content_publisher/src/intents/content_publisher/settings_ui.tsx +0 -81
- package/templates/content_publisher/src/intents/content_publisher/types.ts +0 -29
- package/templates/content_publisher/styles/components.css +0 -38
- package/templates/content_publisher/styles/preview_ui.css +0 -49
- package/templates/content_publisher/tsconfig.json +0 -56
- package/templates/content_publisher/webpack.config.ts +0 -247
- package/templates/dam/backend/routers/dam.ts +0 -108
- package/templates/dam/backend/server.ts +0 -65
- package/templates/dam/canva-app.json +0 -25
- package/templates/dam/declarations/declarations.d.ts +0 -29
- package/templates/dam/eslint.config.mjs +0 -14
- package/templates/dam/package.json +0 -97
- package/templates/dam/scripts/copy_env.ts +0 -13
- package/templates/dam/scripts/ssl/ssl.ts +0 -131
- package/templates/dam/scripts/start/app_runner.ts +0 -223
- package/templates/dam/scripts/start/context.ts +0 -171
- package/templates/dam/scripts/start/start.ts +0 -46
- package/templates/dam/src/index.tsx +0 -4
- package/templates/dam/src/intents/design_editor/adapter.ts +0 -44
- package/templates/dam/src/intents/design_editor/app.tsx +0 -35
- package/templates/dam/src/intents/design_editor/config.ts +0 -220
- package/templates/dam/src/intents/design_editor/index.css +0 -3
- package/templates/dam/src/intents/design_editor/index.tsx +0 -25
- package/templates/dam/tsconfig.json +0 -56
- package/templates/dam/utils/backend/base_backend/create.ts +0 -114
- package/templates/dam/webpack.config.ts +0 -247
- package/templates/data_connector/README.md +0 -84
- package/templates/data_connector/canva-app.json +0 -21
- package/templates/data_connector/declarations/declarations.d.ts +0 -29
- package/templates/data_connector/eslint.config.mjs +0 -14
- package/templates/data_connector/package.json +0 -92
- package/templates/data_connector/scripts/copy_env.ts +0 -13
- package/templates/data_connector/scripts/ssl/ssl.ts +0 -131
- package/templates/data_connector/scripts/start/app_runner.ts +0 -223
- package/templates/data_connector/scripts/start/context.ts +0 -171
- package/templates/data_connector/scripts/start/start.ts +0 -46
- package/templates/data_connector/src/api/connect_client.ts +0 -6
- package/templates/data_connector/src/api/data_source.ts +0 -97
- package/templates/data_connector/src/api/data_sources/designs.tsx +0 -296
- package/templates/data_connector/src/api/data_sources/index.ts +0 -4
- package/templates/data_connector/src/api/data_sources/templates.tsx +0 -328
- package/templates/data_connector/src/api/fetch_data_table.ts +0 -55
- package/templates/data_connector/src/api/index.ts +0 -4
- package/templates/data_connector/src/api/oauth.ts +0 -8
- package/templates/data_connector/src/api/tests/data_source.test.tsx +0 -99
- package/templates/data_connector/src/components/app_error.tsx +0 -15
- package/templates/data_connector/src/components/footer.tsx +0 -26
- package/templates/data_connector/src/components/header.tsx +0 -40
- package/templates/data_connector/src/components/index.ts +0 -3
- package/templates/data_connector/src/components/inputs/messages.tsx +0 -95
- package/templates/data_connector/src/components/inputs/search_filter.tsx +0 -109
- package/templates/data_connector/src/components/inputs/select_field.tsx +0 -26
- package/templates/data_connector/src/context/app_context.tsx +0 -125
- package/templates/data_connector/src/context/index.ts +0 -2
- package/templates/data_connector/src/context/use_app_context.ts +0 -17
- package/templates/data_connector/src/index.tsx +0 -4
- package/templates/data_connector/src/intents/data_connector/app.tsx +0 -20
- package/templates/data_connector/src/intents/data_connector/entrypoint.tsx +0 -70
- package/templates/data_connector/src/intents/data_connector/home.tsx +0 -21
- package/templates/data_connector/src/intents/data_connector/index.tsx +0 -56
- package/templates/data_connector/src/pages/data_source_config.tsx +0 -9
- package/templates/data_connector/src/pages/error.tsx +0 -37
- package/templates/data_connector/src/pages/index.ts +0 -4
- package/templates/data_connector/src/pages/login.tsx +0 -145
- package/templates/data_connector/src/pages/select_source.tsx +0 -24
- package/templates/data_connector/src/routes/index.ts +0 -2
- package/templates/data_connector/src/routes/paths.ts +0 -7
- package/templates/data_connector/src/routes/protected_route.tsx +0 -26
- package/templates/data_connector/src/routes/routes.tsx +0 -42
- package/templates/data_connector/src/utils/data_params.ts +0 -17
- package/templates/data_connector/src/utils/data_table.ts +0 -116
- package/templates/data_connector/src/utils/fetch_result.ts +0 -36
- package/templates/data_connector/src/utils/index.ts +0 -2
- package/templates/data_connector/src/utils/tests/data_table.test.ts +0 -133
- package/templates/data_connector/styles/components.css +0 -38
- package/templates/data_connector/tsconfig.json +0 -56
- package/templates/data_connector/webpack.config.ts +0 -247
- package/templates/gen_ai/README.md +0 -27
- package/templates/gen_ai/backend/routers/image.ts +0 -232
- package/templates/gen_ai/backend/server.ts +0 -65
- package/templates/gen_ai/canva-app.json +0 -25
- package/templates/gen_ai/declarations/declarations.d.ts +0 -29
- package/templates/gen_ai/eslint.config.mjs +0 -14
- package/templates/gen_ai/package.json +0 -101
- package/templates/gen_ai/scripts/copy_env.ts +0 -13
- package/templates/gen_ai/scripts/ssl/ssl.ts +0 -131
- package/templates/gen_ai/scripts/start/app_runner.ts +0 -223
- package/templates/gen_ai/scripts/start/context.ts +0 -171
- package/templates/gen_ai/scripts/start/start.ts +0 -46
- package/templates/gen_ai/src/api/api.ts +0 -194
- package/templates/gen_ai/src/api/index.ts +0 -1
- package/templates/gen_ai/src/components/app_error.tsx +0 -18
- package/templates/gen_ai/src/components/footer.messages.ts +0 -48
- package/templates/gen_ai/src/components/footer.tsx +0 -156
- package/templates/gen_ai/src/components/image_grid.tsx +0 -103
- package/templates/gen_ai/src/components/index.ts +0 -7
- package/templates/gen_ai/src/components/loading_results.tsx +0 -169
- package/templates/gen_ai/src/components/prompt_input.messages.ts +0 -14
- package/templates/gen_ai/src/components/prompt_input.tsx +0 -154
- package/templates/gen_ai/src/components/remaining_credits.tsx +0 -84
- package/templates/gen_ai/src/components/report_box.tsx +0 -54
- package/templates/gen_ai/src/components/tests/remaining_credit.tests.tsx +0 -47
- package/templates/gen_ai/src/config.ts +0 -21
- package/templates/gen_ai/src/context/app_context.tsx +0 -153
- package/templates/gen_ai/src/context/context.messages.ts +0 -30
- package/templates/gen_ai/src/context/index.ts +0 -2
- package/templates/gen_ai/src/context/use_app_context.ts +0 -17
- package/templates/gen_ai/src/index.tsx +0 -4
- package/templates/gen_ai/src/intents/design_editor/app.tsx +0 -19
- package/templates/gen_ai/src/intents/design_editor/home.tsx +0 -13
- package/templates/gen_ai/src/intents/design_editor/index.tsx +0 -17
- package/templates/gen_ai/src/pages/error.tsx +0 -41
- package/templates/gen_ai/src/pages/generate.tsx +0 -9
- package/templates/gen_ai/src/pages/index.ts +0 -3
- package/templates/gen_ai/src/pages/results.tsx +0 -31
- package/templates/gen_ai/src/routes/index.ts +0 -1
- package/templates/gen_ai/src/routes/paths.ts +0 -4
- package/templates/gen_ai/src/routes/routes.tsx +0 -24
- package/templates/gen_ai/src/utils/index.ts +0 -1
- package/templates/gen_ai/src/utils/obscenity_filter.ts +0 -33
- package/templates/gen_ai/styles/components.css +0 -38
- package/templates/gen_ai/styles/utils.css +0 -3
- package/templates/gen_ai/tsconfig.json +0 -56
- package/templates/gen_ai/utils/backend/base_backend/create.ts +0 -114
- package/templates/gen_ai/webpack.config.ts +0 -247
- package/templates/hello_world/canva-app.json +0 -21
- package/templates/hello_world/declarations/declarations.d.ts +0 -29
- package/templates/hello_world/eslint.config.mjs +0 -14
- package/templates/hello_world/package.json +0 -90
- package/templates/hello_world/scripts/copy_env.ts +0 -13
- package/templates/hello_world/scripts/ssl/ssl.ts +0 -131
- package/templates/hello_world/scripts/start/app_runner.ts +0 -223
- package/templates/hello_world/scripts/start/context.ts +0 -171
- package/templates/hello_world/scripts/start/start.ts +0 -46
- package/templates/hello_world/src/index.tsx +0 -4
- package/templates/hello_world/src/intents/design_editor/app.tsx +0 -86
- package/templates/hello_world/src/intents/design_editor/index.tsx +0 -25
- package/templates/hello_world/src/intents/design_editor/tests/__snapshots__/app.tests.tsx.snap +0 -45
- package/templates/hello_world/src/intents/design_editor/tests/app.tests.tsx +0 -92
- package/templates/hello_world/styles/components.css +0 -38
- package/templates/hello_world/tsconfig.json +0 -56
- package/templates/hello_world/webpack.config.ts +0 -247
- package/templates/mls/README.md +0 -81
- package/templates/mls/canva-app.json +0 -25
- package/templates/mls/declarations/declarations.d.ts +0 -29
- package/templates/mls/eslint.config.mjs +0 -14
- package/templates/mls/jest.config.mjs +0 -36
- package/templates/mls/jest.setup.ts +0 -39
- package/templates/mls/package.json +0 -117
- package/templates/mls/scripts/copy_env.ts +0 -13
- package/templates/mls/scripts/ssl/ssl.ts +0 -131
- package/templates/mls/scripts/start/app_runner.ts +0 -223
- package/templates/mls/scripts/start/context.ts +0 -171
- package/templates/mls/scripts/start/start.ts +0 -46
- package/templates/mls/src/__tests__/app.tests.tsx +0 -11
- package/templates/mls/src/__tests__/office_selection_page.tests.tsx +0 -72
- package/templates/mls/src/__tests__/utils.tsx +0 -19
- package/templates/mls/src/adapter.ts +0 -126
- package/templates/mls/src/components/agent/agent_card.tsx +0 -57
- package/templates/mls/src/components/agent/agent_grid.tsx +0 -37
- package/templates/mls/src/components/agent/agent_list.tsx +0 -17
- package/templates/mls/src/components/agent/agent_search_filters.tsx +0 -88
- package/templates/mls/src/components/breadcrumb/breadcrumb.tsx +0 -40
- package/templates/mls/src/components/listing/listing_card.tsx +0 -64
- package/templates/mls/src/components/listing/listing_grid.tsx +0 -37
- package/templates/mls/src/components/listing/listing_list.tsx +0 -21
- package/templates/mls/src/components/listing/listing_search_filters.tsx +0 -145
- package/templates/mls/src/components/placeholders/placeholders.tsx +0 -65
- package/templates/mls/src/data.ts +0 -359
- package/templates/mls/src/index.tsx +0 -4
- package/templates/mls/src/intents/design_editor/app.tsx +0 -44
- package/templates/mls/src/intents/design_editor/index.tsx +0 -25
- package/templates/mls/src/pages/agent_details_page/agent_details_page.tsx +0 -175
- package/templates/mls/src/pages/list_page/agent_tab_panel.tsx +0 -126
- package/templates/mls/src/pages/list_page/list_page.tsx +0 -67
- package/templates/mls/src/pages/list_page/listing_tab_panel.tsx +0 -135
- package/templates/mls/src/pages/listing_details_page/listing_details_page.tsx +0 -418
- package/templates/mls/src/pages/loading_page/loading_page.tsx +0 -152
- package/templates/mls/src/pages/office_selection_page/office_selection_page.tsx +0 -144
- package/templates/mls/src/real_estate.type.ts +0 -44
- package/templates/mls/src/util/use_add_element.tsx +0 -62
- package/templates/mls/src/util/use_drag_element.tsx +0 -68
- package/templates/mls/styles/components.css +0 -38
- package/templates/mls/tsconfig.json +0 -54
- package/templates/mls/webpack.config.ts +0 -248
- package/templates/optional/.cursor/mcp.json +0 -8
- package/templates/optional/.vscode/extensions.json +0 -6
- package/templates/optional/.vscode/mcp.json +0 -9
- package/templates/optional/AGENTS.md +0 -154
- package/templates/optional/CLAUDE.md +0 -154
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/* Scroll container */
|
|
2
|
-
.scrollContainer {
|
|
3
|
-
box-sizing: border-box;
|
|
4
|
-
overflow-y: scroll;
|
|
5
|
-
height: 100%;
|
|
6
|
-
padding-top: var(--ui-kit-space-200);
|
|
7
|
-
padding-right: var(--ui-kit-space-200);
|
|
8
|
-
padding-bottom: var(--ui-kit-space-200);
|
|
9
|
-
|
|
10
|
-
/* for firefox */
|
|
11
|
-
scrollbar-width: thin;
|
|
12
|
-
scrollbar-color: var(--ui-kit-color-content-placeholder-fg) transparent;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.scrollContainer::-webkit-scrollbar {
|
|
16
|
-
position: absolute;
|
|
17
|
-
width: var(--ui-kit-base-unit);
|
|
18
|
-
height: 0;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.scrollContainer::-webkit-scrollbar-track {
|
|
22
|
-
background: transparent;
|
|
23
|
-
width: var(--ui-kit-base-unit);
|
|
24
|
-
margin-top: var(--ui-kit-space-100);
|
|
25
|
-
margin-bottom: var(--ui-kit-space-100);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.scrollContainer::-webkit-scrollbar-thumb {
|
|
29
|
-
border-radius: var(--ui-kit-radius-element-standard);
|
|
30
|
-
background: var(--ui-kit-color-content-placeholder-fg);
|
|
31
|
-
visibility: hidden;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.scrollContainer:hover::-webkit-scrollbar-thumb,
|
|
35
|
-
.scrollContainer:focus::-webkit-scrollbar-thumb,
|
|
36
|
-
.scrollContainer:focus-within::-webkit-scrollbar-thumb {
|
|
37
|
-
visibility: visible;
|
|
38
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"jsx": "react-jsx",
|
|
4
|
-
"lib": [
|
|
5
|
-
"dom",
|
|
6
|
-
"dom.iterable",
|
|
7
|
-
"es2018",
|
|
8
|
-
"es2019.array",
|
|
9
|
-
"es2019.object",
|
|
10
|
-
"es2019.string",
|
|
11
|
-
"es2020.promise",
|
|
12
|
-
"es2020.string"
|
|
13
|
-
],
|
|
14
|
-
"types": ["node", "webpack-env", "jest"],
|
|
15
|
-
"composite": false,
|
|
16
|
-
"declaration": false,
|
|
17
|
-
"declarationMap": false,
|
|
18
|
-
"experimentalDecorators": true,
|
|
19
|
-
"importHelpers": true,
|
|
20
|
-
"noImplicitOverride": true,
|
|
21
|
-
"moduleResolution": "bundler",
|
|
22
|
-
"esModuleInterop": true,
|
|
23
|
-
"rootDir": ".",
|
|
24
|
-
"outDir": "dist",
|
|
25
|
-
"strict": true,
|
|
26
|
-
"skipLibCheck": true,
|
|
27
|
-
"target": "ES2019",
|
|
28
|
-
"sourceMap": true,
|
|
29
|
-
"inlineSources": true,
|
|
30
|
-
"module": "ESNext",
|
|
31
|
-
"noImplicitAny": true,
|
|
32
|
-
"noImplicitReturns": true,
|
|
33
|
-
"noFallthroughCasesInSwitch": true,
|
|
34
|
-
"noUncheckedIndexedAccess": true,
|
|
35
|
-
"removeComments": true,
|
|
36
|
-
"preserveConstEnums": true,
|
|
37
|
-
"allowSyntheticDefaultImports": true,
|
|
38
|
-
"baseUrl": "./",
|
|
39
|
-
"paths": {
|
|
40
|
-
"styles": ["./styles"]
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
"include": [
|
|
44
|
-
"./src/**/*",
|
|
45
|
-
"./backend/**/*",
|
|
46
|
-
"./utils/**/*",
|
|
47
|
-
"./scripts/**/*",
|
|
48
|
-
"./declarations/declarations.d.ts",
|
|
49
|
-
"./styles/**/*"
|
|
50
|
-
],
|
|
51
|
-
"ts-node": {
|
|
52
|
-
"compilerOptions": {
|
|
53
|
-
"module": "commonjs"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import type { Configuration } from "webpack";
|
|
2
|
-
import { DefinePlugin, optimize } from "webpack";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import TerserPlugin from "terser-webpack-plugin";
|
|
5
|
-
import { transform } from "@formatjs/ts-transformer";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
import { config } from "dotenv";
|
|
8
|
-
import { Configuration as DevServerConfiguration } from "webpack-dev-server";
|
|
9
|
-
|
|
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({
|
|
23
|
-
devConfig,
|
|
24
|
-
appEntry = path.join(process.cwd(), "src", "index.tsx"),
|
|
25
|
-
backendHost = process.env.CANVA_BACKEND_HOST,
|
|
26
|
-
// For IN_HARNESS, refer to the following docs for more information: https://www.canva.dev/docs/apps/test-harness/
|
|
27
|
-
inHarness = process.env.IN_HARNESS?.toLowerCase() === "true",
|
|
28
|
-
}: {
|
|
29
|
-
devConfig?: DevConfig;
|
|
30
|
-
appEntry?: string;
|
|
31
|
-
backendHost?: string;
|
|
32
|
-
inHarness?: boolean;
|
|
33
|
-
} = {}): Configuration & DevServerConfiguration {
|
|
34
|
-
const mode = devConfig ? "development" : "production";
|
|
35
|
-
|
|
36
|
-
if (!backendHost) {
|
|
37
|
-
console.warn(
|
|
38
|
-
chalk.yellow.bold("BACKEND_HOST is undefined."),
|
|
39
|
-
`If your app requires a backend, refer to "Customizing the backend host" in the README.md for more information.`,
|
|
40
|
-
);
|
|
41
|
-
} else if (backendHost.includes("localhost") && mode === "production") {
|
|
42
|
-
console.error(
|
|
43
|
-
chalk.redBright.bold(
|
|
44
|
-
"BACKEND_HOST should not be set to localhost for production builds!",
|
|
45
|
-
),
|
|
46
|
-
`Refer to "Customizing the backend host" in the README.md for more information.`,
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
mode,
|
|
52
|
-
context: path.resolve(process.cwd(), "./"),
|
|
53
|
-
entry: inHarness
|
|
54
|
-
? {
|
|
55
|
-
harness: path.join(process.cwd(), "harness", "harness.tsx"),
|
|
56
|
-
init: path.join(process.cwd(), "harness", "init.ts"),
|
|
57
|
-
}
|
|
58
|
-
: {
|
|
59
|
-
app: appEntry,
|
|
60
|
-
},
|
|
61
|
-
target: "web",
|
|
62
|
-
resolve: {
|
|
63
|
-
alias: {
|
|
64
|
-
styles: path.resolve(process.cwd(), "styles"),
|
|
65
|
-
src: path.resolve(process.cwd(), "src"),
|
|
66
|
-
},
|
|
67
|
-
extensions: [".ts", ".tsx", ".js", ".css", ".svg", ".woff", ".woff2"],
|
|
68
|
-
},
|
|
69
|
-
infrastructureLogging: {
|
|
70
|
-
level: inHarness ? "info" : "none",
|
|
71
|
-
},
|
|
72
|
-
module: {
|
|
73
|
-
rules: [
|
|
74
|
-
{
|
|
75
|
-
test: /\.tsx?$/,
|
|
76
|
-
exclude: /node_modules/,
|
|
77
|
-
use: [
|
|
78
|
-
{
|
|
79
|
-
loader: "ts-loader",
|
|
80
|
-
options: {
|
|
81
|
-
transpileOnly: true,
|
|
82
|
-
getCustomTransformers() {
|
|
83
|
-
return {
|
|
84
|
-
before: [
|
|
85
|
-
transform({
|
|
86
|
-
overrideIdFn: "[sha512:contenthash:base64:6]",
|
|
87
|
-
}),
|
|
88
|
-
],
|
|
89
|
-
};
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
],
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
test: /\.css$/,
|
|
97
|
-
exclude: /node_modules/,
|
|
98
|
-
use: [
|
|
99
|
-
"style-loader",
|
|
100
|
-
{
|
|
101
|
-
loader: "css-loader",
|
|
102
|
-
options: {
|
|
103
|
-
modules: true,
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
loader: "postcss-loader",
|
|
108
|
-
options: {
|
|
109
|
-
postcssOptions: {
|
|
110
|
-
plugins: [require("cssnano")({ preset: "default" })],
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
],
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
test: /\.(png|jpg|jpeg)$/i,
|
|
118
|
-
type: "asset/inline",
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
test: /\.(woff|woff2)$/,
|
|
122
|
-
type: "asset/inline",
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
test: /\.svg$/,
|
|
126
|
-
oneOf: [
|
|
127
|
-
{
|
|
128
|
-
issuer: /\.[jt]sx?$/,
|
|
129
|
-
resourceQuery: /react/, // *.svg?react
|
|
130
|
-
use: ["@svgr/webpack", "url-loader"],
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
type: "asset/resource",
|
|
134
|
-
parser: {
|
|
135
|
-
dataUrlCondition: {
|
|
136
|
-
maxSize: 200,
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
test: /\.css$/,
|
|
144
|
-
include: /node_modules/,
|
|
145
|
-
use: [
|
|
146
|
-
"style-loader",
|
|
147
|
-
"css-loader",
|
|
148
|
-
{
|
|
149
|
-
loader: "postcss-loader",
|
|
150
|
-
options: {
|
|
151
|
-
postcssOptions: {
|
|
152
|
-
plugins: [require("cssnano")({ preset: "default" })],
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
],
|
|
159
|
-
},
|
|
160
|
-
optimization: {
|
|
161
|
-
minimizer: [
|
|
162
|
-
new TerserPlugin({
|
|
163
|
-
terserOptions: {
|
|
164
|
-
format: {
|
|
165
|
-
// Turned on because emoji and regex is not minified properly using default
|
|
166
|
-
// https://github.com/facebook/create-react-app/issues/2488
|
|
167
|
-
ascii_only: true,
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
}),
|
|
171
|
-
],
|
|
172
|
-
},
|
|
173
|
-
output: {
|
|
174
|
-
filename: `[name].js`,
|
|
175
|
-
path: path.resolve(process.cwd(), "dist"),
|
|
176
|
-
clean: true,
|
|
177
|
-
},
|
|
178
|
-
plugins: [
|
|
179
|
-
new DefinePlugin({
|
|
180
|
-
BACKEND_HOST: JSON.stringify(backendHost),
|
|
181
|
-
}),
|
|
182
|
-
// Apps can only submit a single JS file via the Developer Portal
|
|
183
|
-
new optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
|
184
|
-
].filter(Boolean),
|
|
185
|
-
...buildDevConfig(devConfig),
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function buildDevConfig(options?: DevConfig): {
|
|
190
|
-
devtool?: string;
|
|
191
|
-
devServer?: DevServerConfiguration;
|
|
192
|
-
} {
|
|
193
|
-
if (!options) {
|
|
194
|
-
return {};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const { port, enableHmr, appOrigin, enableHttps, certFile, keyFile } =
|
|
198
|
-
options;
|
|
199
|
-
const host = "localhost";
|
|
200
|
-
|
|
201
|
-
let devServer: DevServerConfiguration = {
|
|
202
|
-
server: enableHttps
|
|
203
|
-
? {
|
|
204
|
-
type: "https",
|
|
205
|
-
options: {
|
|
206
|
-
cert: certFile,
|
|
207
|
-
key: keyFile,
|
|
208
|
-
},
|
|
209
|
-
}
|
|
210
|
-
: "http",
|
|
211
|
-
host,
|
|
212
|
-
allowedHosts: [host],
|
|
213
|
-
historyApiFallback: {
|
|
214
|
-
rewrites: [{ from: /^\/$/, to: "/app.js" }],
|
|
215
|
-
},
|
|
216
|
-
port,
|
|
217
|
-
client: {
|
|
218
|
-
logging: "verbose",
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
if (enableHmr && appOrigin) {
|
|
223
|
-
devServer = {
|
|
224
|
-
...devServer,
|
|
225
|
-
allowedHosts: [host, new URL(appOrigin).hostname],
|
|
226
|
-
headers: {
|
|
227
|
-
"Access-Control-Allow-Origin": appOrigin,
|
|
228
|
-
"Access-Control-Allow-Credentials": "true",
|
|
229
|
-
"Access-Control-Allow-Private-Network": "true",
|
|
230
|
-
},
|
|
231
|
-
};
|
|
232
|
-
} else {
|
|
233
|
-
if (enableHmr && !appOrigin) {
|
|
234
|
-
console.warn(
|
|
235
|
-
"Attempted to enable Hot Module Replacement (HMR) without configuring App Origin... Disabling HMR.",
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
devServer.webSocketServer = false;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
devtool: "source-map",
|
|
243
|
-
devServer,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export default buildConfig;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
## Generative AI Template
|
|
2
|
-
|
|
3
|
-
This template captures best practices for improving user experience in your application.
|
|
4
|
-
|
|
5
|
-
### State Management
|
|
6
|
-
|
|
7
|
-
In this template, we've set up state management using `React Context`. It's just one way to do it, not a strict rule. If your app gets more complicated, you might want to check out other options like `Redux` or `MobX`.
|
|
8
|
-
|
|
9
|
-
### Routing
|
|
10
|
-
|
|
11
|
-
As your application evolves, you may find the need for routing to manage multiple views or pages. In this template, we've integrated React Router to illustrate how routing can facilitate seamless navigation between various components.
|
|
12
|
-
|
|
13
|
-
### Loading state
|
|
14
|
-
|
|
15
|
-
Creating AI assets can be time-consuming, often resulting in users facing extended waiting periods. Incorporating placeholders, a loading bar, and a message indicating the expected wait time can help alleviate the perceived wait time. We highly encourage adopting this approach and customizing it to suit your specific use case.
|
|
16
|
-
|
|
17
|
-
### Obscenity filter
|
|
18
|
-
|
|
19
|
-
In this template, we've included a basic obscenity filter to stop users from creating offensive or harmful content. However, you might need additional filters or checks after content generation to ensure it meets your standards.
|
|
20
|
-
|
|
21
|
-
### Backend
|
|
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. 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
|
-
|
|
25
|
-
### Thumbnails
|
|
26
|
-
|
|
27
|
-
This template illustrates how your API could return thumbnails and demonstrates their usage within the code. Thumbnails play a crucial role in optimizing image uploads and previews by providing quick visual feedback and reducing load times.
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DISCLAIMER:
|
|
3
|
-
* This file contains a demonstration of how to implement a simple API with Express.js for educational purposes only.
|
|
4
|
-
* It is NOT SUITABLE for use in a production environment. It lacks many essential features such as error handling,
|
|
5
|
-
* input validation, authentication, and security measures. Additionally, the in-memory job queue is for illustrative
|
|
6
|
-
* purposes only and is not efficient or scalable. For production use, consider using robust libraries and frameworks,
|
|
7
|
-
* implementing proper error handling, security measures, and using appropriate database and job queue solutions.
|
|
8
|
-
* Use this code as a learning resource, but do not deploy it in a real backend without significant modifications
|
|
9
|
-
* to ensure reliability, security, and scalability.
|
|
10
|
-
*/
|
|
11
|
-
import express from "express";
|
|
12
|
-
|
|
13
|
-
interface ImageResponse {
|
|
14
|
-
fullsize: { width: number; height: number; url: string };
|
|
15
|
-
thumbnail: { width: number; height: number; url: string };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Array of placeholder image URLs.
|
|
19
|
-
// In a real-world scenario, these URLs would point to dynamically generated images.
|
|
20
|
-
const imageUrls: ImageResponse[] = [
|
|
21
|
-
{
|
|
22
|
-
fullsize: {
|
|
23
|
-
width: 1280,
|
|
24
|
-
height: 853,
|
|
25
|
-
url: "https://images.pexels.com/photos/1145720/pexels-photo-1145720.jpeg?auto=compress&cs=tinysrgb&w=1280&h=853&dpr=2",
|
|
26
|
-
},
|
|
27
|
-
thumbnail: {
|
|
28
|
-
width: 640,
|
|
29
|
-
height: 427,
|
|
30
|
-
url: "https://images.pexels.com/photos/1145720/pexels-photo-1145720.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
fullsize: {
|
|
35
|
-
width: 1280,
|
|
36
|
-
height: 853,
|
|
37
|
-
url: "https://images.pexels.com/photos/4010108/pexels-photo-4010108.jpeg?auto=compress&cs=tinysrgb&w=1280&h=863&dpr=2",
|
|
38
|
-
},
|
|
39
|
-
thumbnail: {
|
|
40
|
-
width: 640,
|
|
41
|
-
height: 427,
|
|
42
|
-
url: "https://images.pexels.com/photos/4010108/pexels-photo-4010108.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
fullsize: {
|
|
47
|
-
width: 1280,
|
|
48
|
-
height: 853,
|
|
49
|
-
url: "https://images.pexels.com/photos/1327496/pexels-photo-1327496.jpeg?auto=compress&cs=tinysrgb&w=1280&h=853&dpr=2",
|
|
50
|
-
},
|
|
51
|
-
thumbnail: {
|
|
52
|
-
width: 640,
|
|
53
|
-
height: 427,
|
|
54
|
-
url: "https://images.pexels.com/photos/1327496/pexels-photo-1327496.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
fullsize: {
|
|
59
|
-
width: 1280,
|
|
60
|
-
height: 853,
|
|
61
|
-
url: "https://images.pexels.com/photos/4693135/pexels-photo-4693135.jpeg?auto=compress&cs=tinysrgb&w=1280&h=853&dpr=2",
|
|
62
|
-
},
|
|
63
|
-
thumbnail: {
|
|
64
|
-
width: 640,
|
|
65
|
-
height: 427,
|
|
66
|
-
url: "https://images.pexels.com/photos/4693135/pexels-photo-4693135.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
export const createImageRouter = () => {
|
|
72
|
-
const enum Routes {
|
|
73
|
-
CREDITS = "/api/credits",
|
|
74
|
-
PURCHASE_CREDITS = "/api/purchase-credits",
|
|
75
|
-
QUEUE_IMAGE_GENERATION = "/api/queue-image-generation",
|
|
76
|
-
JOB_STATUS = "/api/job-status",
|
|
77
|
-
CANCEL_JOB = "/api/job-status/cancel",
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const router = express.Router();
|
|
81
|
-
const jobQueue: {
|
|
82
|
-
jobId: string;
|
|
83
|
-
prompt: string;
|
|
84
|
-
timeoutId: NodeJS.Timeout;
|
|
85
|
-
}[] = [];
|
|
86
|
-
const completedJobs: Record<string, ImageResponse[]> = {};
|
|
87
|
-
const cancelledJobs: { jobId: string }[] = [];
|
|
88
|
-
|
|
89
|
-
// Initial credit allocation for users, which decreases with each use.
|
|
90
|
-
// Users receive 10 credits initially and can purchase additional credits in bundles.
|
|
91
|
-
let credits = 10;
|
|
92
|
-
const CREDITS_IN_BUNDLE = 10;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* GET endpoint to retrieve user credits.
|
|
96
|
-
* Returns the current number of credits available to the user.
|
|
97
|
-
*/
|
|
98
|
-
router.get(Routes.CREDITS, async (req, res) => {
|
|
99
|
-
res.status(200).send({
|
|
100
|
-
credits,
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* POST endpoint to purchase credits.
|
|
106
|
-
* Increments the user's credits by the number of credits in a bundle.
|
|
107
|
-
* This endpoint should be backed by proper input validation to prevent misuse.
|
|
108
|
-
*/
|
|
109
|
-
router.post(Routes.PURCHASE_CREDITS, async (req, res) => {
|
|
110
|
-
credits += CREDITS_IN_BUNDLE;
|
|
111
|
-
res.status(200).send({
|
|
112
|
-
credits,
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* GET endpoint to generate images based on a prompt.
|
|
118
|
-
* Generates images based on the provided prompt and adds a job to the processing queue.
|
|
119
|
-
* If there are not enough credits, it returns a 403 error.
|
|
120
|
-
* If the prompt parameter is missing, it returns a 400 error.
|
|
121
|
-
* Once the job is added to the queue, it returns a jobId that can be used to check the job status.
|
|
122
|
-
* Note: The job processing time is simulated to be 5 seconds.
|
|
123
|
-
*/
|
|
124
|
-
router.get(Routes.QUEUE_IMAGE_GENERATION, async (req, res) => {
|
|
125
|
-
if (credits <= 0) {
|
|
126
|
-
return res
|
|
127
|
-
.status(403)
|
|
128
|
-
.send("Not enough credits required to generate images.");
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const prompt = req.query.prompt as string;
|
|
132
|
-
if (!prompt) {
|
|
133
|
-
return res.status(400).send("Missing prompt parameter.");
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const jobId = generateJobId();
|
|
137
|
-
|
|
138
|
-
const timeoutId = setTimeout(() => {
|
|
139
|
-
const index = jobQueue.findIndex((job) => job.jobId === jobId);
|
|
140
|
-
if (index !== -1) {
|
|
141
|
-
jobQueue.splice(index, 1);
|
|
142
|
-
completedJobs[jobId] = imageUrls.map((image) => {
|
|
143
|
-
return { ...image, label: prompt };
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// Reduce credits by 1 when images are successfully generated
|
|
147
|
-
credits -= 1;
|
|
148
|
-
}
|
|
149
|
-
}, 5000); // Simulating 5 seconds processing time
|
|
150
|
-
|
|
151
|
-
// Add the job to the jobQueue along with the timeoutId
|
|
152
|
-
jobQueue.push({ jobId, prompt, timeoutId });
|
|
153
|
-
|
|
154
|
-
return res.status(200).send({
|
|
155
|
-
jobId,
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* GET endpoint to check the status of a job.
|
|
161
|
-
* Retrieves the status of a job identified by its jobId parameter.
|
|
162
|
-
* If the job is completed, it returns the images generated by the job.
|
|
163
|
-
* If the job is still in the processing queue, it returns "processing".
|
|
164
|
-
* If the job has been cancelled, it returns "cancelled".
|
|
165
|
-
* If the job is not found, it returns a 404 error.
|
|
166
|
-
*/
|
|
167
|
-
router.get(Routes.JOB_STATUS, async (req, res) => {
|
|
168
|
-
const jobId = req.query.jobId as string;
|
|
169
|
-
|
|
170
|
-
if (!jobId) {
|
|
171
|
-
return res.status(400).send("Missing jobId parameter.");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (completedJobs[jobId]) {
|
|
175
|
-
return res.status(200).send({
|
|
176
|
-
status: "completed",
|
|
177
|
-
images: completedJobs[jobId],
|
|
178
|
-
credits,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (jobQueue.some((job) => job.jobId === jobId)) {
|
|
183
|
-
return res.status(200).send({
|
|
184
|
-
status: "processing",
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (cancelledJobs.some((job) => job.jobId === jobId)) {
|
|
189
|
-
return res.status(200).send({
|
|
190
|
-
status: "cancelled",
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return res.status(404).send("Job not found.");
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* POST endpoint to cancel a job.
|
|
199
|
-
* Cancels a job identified by its jobId parameter.
|
|
200
|
-
* If the job is found and successfully cancelled, it removes the job from the processing queue and adds it to the cancelled jobs array.
|
|
201
|
-
* If the job is not found, it returns a 404 error.
|
|
202
|
-
*/
|
|
203
|
-
router.post(Routes.CANCEL_JOB, async (req, res) => {
|
|
204
|
-
const jobId = req.query.jobId as string;
|
|
205
|
-
|
|
206
|
-
if (!jobId) {
|
|
207
|
-
return res.status(400).send("Missing jobId parameter.");
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const index = jobQueue.findIndex((job) => job.jobId === jobId);
|
|
211
|
-
const job = jobQueue[index];
|
|
212
|
-
if (index !== -1 && job) {
|
|
213
|
-
cancelledJobs.push({ jobId });
|
|
214
|
-
// If the job is found, remove it from the jobQueue
|
|
215
|
-
jobQueue.splice(index, 1);
|
|
216
|
-
// Also clear the timeout associated with this job if it exists
|
|
217
|
-
clearTimeout(job.timeoutId);
|
|
218
|
-
return res.status(200).send("Job successfully cancelled.");
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return res.status(404).send("Job not found.");
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Generates a unique job ID.
|
|
226
|
-
*/
|
|
227
|
-
function generateJobId(): string {
|
|
228
|
-
return Math.random().toString(36).substring(2, 15);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return router;
|
|
232
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { user } from "@canva/app-middleware/express";
|
|
2
|
-
import cors from "cors";
|
|
3
|
-
import express from "express";
|
|
4
|
-
import { createBaseServer } from "../utils/backend/base_backend/create";
|
|
5
|
-
import { createImageRouter } from "./routers/image";
|
|
6
|
-
|
|
7
|
-
async function main() {
|
|
8
|
-
// TODO: Set the CANVA_APP_ID environment variable in the project's .env file
|
|
9
|
-
const APP_ID = process.env.CANVA_APP_ID;
|
|
10
|
-
|
|
11
|
-
if (!APP_ID) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
`The CANVA_APP_ID environment variable is undefined. Set the variable in the project's .env file.`,
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const router = express.Router();
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* TODO: Configure your CORS Policy
|
|
21
|
-
*
|
|
22
|
-
* Cross-Origin Resource Sharing
|
|
23
|
-
* ([CORS](https://developer.mozilla.org/en-US/docs/Glossary/CORS)) is an
|
|
24
|
-
* [HTTP](https://developer.mozilla.org/en-US/docs/Glossary/HTTP)-header based
|
|
25
|
-
* mechanism that allows a server to indicate any
|
|
26
|
-
* [origins](https://developer.mozilla.org/en-US/docs/Glossary/Origin)
|
|
27
|
-
* (domain, scheme, or port) other than its own from which a browser should
|
|
28
|
-
* permit loading resources.
|
|
29
|
-
*
|
|
30
|
-
* A basic CORS configuration would include the origin of your app in the
|
|
31
|
-
* following example:
|
|
32
|
-
* const corsOptions = {
|
|
33
|
-
* origin: 'https://app-abcdefg.canva-apps.com',
|
|
34
|
-
* optionsSuccessStatus: 200
|
|
35
|
-
* }
|
|
36
|
-
*
|
|
37
|
-
* The origin of your app is https://app-${APP_ID}.canva-apps.com, and note
|
|
38
|
-
* that the APP_ID should to be converted to lowercase.
|
|
39
|
-
*
|
|
40
|
-
* https://www.npmjs.com/package/cors#configuring-cors
|
|
41
|
-
*
|
|
42
|
-
* You may need to include multiple permissible origins, or dynamic origins
|
|
43
|
-
* based on the environment in which the server is running. Further
|
|
44
|
-
* information can be found
|
|
45
|
-
* [here](https://www.npmjs.com/package/cors#configuring-cors-w-dynamic-origin).
|
|
46
|
-
*/
|
|
47
|
-
router.use(cors());
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Initialize JWT middleware to verify Canva user tokens
|
|
51
|
-
* This middleware validates tokens sent from the frontend and extracts user information
|
|
52
|
-
*/
|
|
53
|
-
router.use(user.verifyToken({ appId: APP_ID }));
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Add routes for image generation.
|
|
57
|
-
*/
|
|
58
|
-
const imageRouter = createImageRouter();
|
|
59
|
-
router.use(imageRouter);
|
|
60
|
-
|
|
61
|
-
const server = createBaseServer(router);
|
|
62
|
-
server.start(process.env.CANVA_BACKEND_PORT);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
main();
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://www.canva.dev/schemas/app/v1/manifest-schema.json",
|
|
3
|
-
"manifest_schema_version": 1,
|
|
4
|
-
"runtime": {
|
|
5
|
-
"permissions": [
|
|
6
|
-
{
|
|
7
|
-
"name": "canva:asset:private:write",
|
|
8
|
-
"type": "mandatory"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"name": "canva:design:content:read",
|
|
12
|
-
"type": "mandatory"
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"name": "canva:design:content:write",
|
|
16
|
-
"type": "mandatory"
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
},
|
|
20
|
-
"intent": {
|
|
21
|
-
"design_editor": {
|
|
22
|
-
"enrolled": true
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|