@canva/cli 1.14.0 → 1.16.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 +19 -0
- package/README.md +1 -0
- package/cli.js +308 -308
- package/package.json +1 -1
- package/templates/base/backend/base_backend/create.ts +10 -0
- package/templates/base/backend/routers/auth.ts +12 -9
- package/templates/base/package.json +3 -3
- package/templates/content_publisher/README.md +58 -0
- package/templates/content_publisher/canva-app.json +17 -0
- package/templates/content_publisher/declarations/declarations.d.ts +29 -0
- package/templates/content_publisher/eslint.config.mjs +14 -0
- package/templates/content_publisher/package.json +90 -0
- package/templates/content_publisher/scripts/copy_env.ts +13 -0
- package/templates/content_publisher/scripts/ssl/ssl.ts +131 -0
- package/templates/content_publisher/scripts/start/app_runner.ts +223 -0
- package/templates/content_publisher/scripts/start/context.ts +171 -0
- package/templates/content_publisher/scripts/start/start.ts +46 -0
- package/templates/content_publisher/src/index.tsx +4 -0
- package/templates/content_publisher/src/intents/content_publisher/index.tsx +113 -0
- package/templates/content_publisher/src/intents/content_publisher/post_preview.tsx +226 -0
- package/templates/content_publisher/src/intents/content_publisher/preview_ui.tsx +53 -0
- package/templates/content_publisher/src/intents/content_publisher/settings_ui.tsx +71 -0
- package/templates/content_publisher/src/intents/content_publisher/types.ts +29 -0
- package/templates/content_publisher/styles/components.css +56 -0
- package/templates/content_publisher/styles/preview_ui.css +88 -0
- package/templates/content_publisher/tsconfig.json +56 -0
- package/templates/content_publisher/webpack.config.ts +247 -0
- package/templates/dam/backend/server.ts +2 -3
- package/templates/dam/package.json +5 -4
- package/templates/dam/utils/backend/base_backend/create.ts +10 -0
- package/templates/data_connector/package.json +3 -3
- package/templates/gen_ai/backend/server.ts +2 -3
- package/templates/gen_ai/package.json +4 -3
- package/templates/gen_ai/utils/backend/base_backend/create.ts +10 -0
- package/templates/hello_world/package.json +3 -3
- package/templates/mls/package.json +3 -3
- package/templates/base/backend/jwt_middleware/index.ts +0 -1
- package/templates/base/backend/jwt_middleware/jwt_middleware.ts +0 -224
- package/templates/dam/utils/backend/jwt_middleware/index.ts +0 -1
- package/templates/dam/utils/backend/jwt_middleware/jwt_middleware.ts +0 -224
- package/templates/gen_ai/utils/backend/jwt_middleware/index.ts +0 -1
- package/templates/gen_ai/utils/backend/jwt_middleware/jwt_middleware.ts +0 -224
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definition for publish settings.
|
|
3
|
+
* These settings are serialized and passed between different parts of the publish flow.
|
|
4
|
+
* In production, include all platform-specific settings needed for publishing.
|
|
5
|
+
*/
|
|
6
|
+
export interface PublishSettings {
|
|
7
|
+
caption: string;
|
|
8
|
+
// TODO: Add additional fields for your platform's publishing requirements
|
|
9
|
+
// Examples:
|
|
10
|
+
// scheduledTime: Date;
|
|
11
|
+
// visibility: "public" | "private" | "unlisted";
|
|
12
|
+
// tags: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Utility function to safely parse publish settings from a JSON string.
|
|
17
|
+
* This is used to deserialize settings that were passed through the publish flow.
|
|
18
|
+
*/
|
|
19
|
+
export function parsePublishSettings(
|
|
20
|
+
publishRef?: string,
|
|
21
|
+
): PublishSettings | undefined {
|
|
22
|
+
if (!publishRef) return undefined;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(publishRef) as PublishSettings;
|
|
26
|
+
} catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Main container for the content publisher preview UI */
|
|
41
|
+
.previewContainer {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Wrapper for the content publisher post preview */
|
|
51
|
+
.previewWrapper {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
width: calc(400px + 32px + 2px); /* Image width + padding + border */
|
|
56
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/* Main container for the preview UI */
|
|
2
|
+
.container {
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: 100%;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* Scale down preview on mobile devices */
|
|
12
|
+
@media (max-width: 600px) {
|
|
13
|
+
.container {
|
|
14
|
+
transform: scale(0.3);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Wrapper for the social media post preview */
|
|
19
|
+
.wrapper {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
width: calc(400px + 32px + 2px); /* Image width + padding + border */
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* User profile section styling */
|
|
27
|
+
.user {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 8px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Avatar styling to match social media appearance */
|
|
34
|
+
.avatar {
|
|
35
|
+
transform: scale(0.6);
|
|
36
|
+
width: 24px;
|
|
37
|
+
height: 24px;
|
|
38
|
+
transform-origin: top left;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.avatarImage {
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
object-fit: cover;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Text placeholder for loading states */
|
|
48
|
+
.textPlaceholder {
|
|
49
|
+
min-width: calc(8 * 20);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Container for media images */
|
|
53
|
+
.imageContainer {
|
|
54
|
+
overflow: hidden; /* Enable border radius */
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Row containing all images */
|
|
58
|
+
.imageRow {
|
|
59
|
+
overflow-y: hidden;
|
|
60
|
+
overflow-x: auto;
|
|
61
|
+
height: 400px;
|
|
62
|
+
display: flex;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Aspect ratio helpers for different image formats */
|
|
66
|
+
.aspect-1-1 {
|
|
67
|
+
padding-top: 100%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.aspect-3-4 {
|
|
71
|
+
padding-top: 133.33%;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Individual image and placeholder styling */
|
|
75
|
+
.imagePlaceholder,
|
|
76
|
+
.image {
|
|
77
|
+
width: 400px;
|
|
78
|
+
height: 400px;
|
|
79
|
+
object-fit: cover;
|
|
80
|
+
display: inline-block;
|
|
81
|
+
position: relative;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Icon placeholder styling */
|
|
85
|
+
.iconPlaceholder {
|
|
86
|
+
width: 24px;
|
|
87
|
+
height: 24px;
|
|
88
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
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,7 +1,7 @@
|
|
|
1
|
+
import { user } from "@canva/app-middleware/express";
|
|
1
2
|
import cors from "cors";
|
|
2
3
|
import express from "express";
|
|
3
4
|
import { createBaseServer } from "../utils/backend/base_backend/create";
|
|
4
|
-
import { createJwtMiddleware } from "../utils/backend/jwt_middleware";
|
|
5
5
|
import { createDamRouter } from "./routers/dam";
|
|
6
6
|
|
|
7
7
|
async function main() {
|
|
@@ -50,8 +50,7 @@ async function main() {
|
|
|
50
50
|
* Initialize JWT middleware to verify Canva user tokens
|
|
51
51
|
* This middleware validates tokens sent from the frontend and extracts user information
|
|
52
52
|
*/
|
|
53
|
-
|
|
54
|
-
router.use(jwtMiddleware);
|
|
53
|
+
router.use(user.verifyToken({ appId: APP_ID }));
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* Add routes for digital asset management.
|
|
@@ -18,15 +18,16 @@
|
|
|
18
18
|
"postinstall": "ts-node ./scripts/copy_env.ts"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
22
21
|
"@canva/app-components": "^2.1.0",
|
|
22
|
+
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
23
23
|
"@canva/app-i18n-kit": "^1.2.0",
|
|
24
|
-
"@canva/app-
|
|
24
|
+
"@canva/app-middleware": "^0.0.0-beta.5",
|
|
25
|
+
"@canva/app-ui-kit": "^5.5.0",
|
|
25
26
|
"@canva/asset": "^2.3.0",
|
|
26
27
|
"@canva/design": "^2.7.5",
|
|
27
|
-
"@canva/error": "^2.
|
|
28
|
+
"@canva/error": "^2.2.0",
|
|
28
29
|
"@canva/intents": "^2.0.0",
|
|
29
|
-
"@canva/platform": "^2.2.
|
|
30
|
+
"@canva/platform": "^2.2.1",
|
|
30
31
|
"@canva/user": "^2.1.2",
|
|
31
32
|
"cookie-parser": "1.4.7",
|
|
32
33
|
"cors": "2.8.5",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import { TokenVerificationError } from "@canva/app-middleware";
|
|
2
3
|
import debug from "debug";
|
|
3
4
|
import express from "express";
|
|
4
5
|
import type { NextFunction, Request, Response } from "express";
|
|
@@ -63,6 +64,15 @@ export function createBaseServer(router: express.Router): BaseServer {
|
|
|
63
64
|
|
|
64
65
|
// default error handler
|
|
65
66
|
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
|
67
|
+
// Handle authentication errors from @canva/app-middleware
|
|
68
|
+
if (err instanceof TokenVerificationError) {
|
|
69
|
+
res.status(err.statusCode).json({
|
|
70
|
+
error: err.code,
|
|
71
|
+
message: err.message,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
66
76
|
console.error(err.stack);
|
|
67
77
|
res.status(500).send({
|
|
68
78
|
error: "something went wrong",
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
23
23
|
"@canva/app-i18n-kit": "^1.2.0",
|
|
24
|
-
"@canva/app-ui-kit": "^5.
|
|
24
|
+
"@canva/app-ui-kit": "^5.5.0",
|
|
25
25
|
"@canva/asset": "^2.3.0",
|
|
26
26
|
"@canva/design": "^2.7.5",
|
|
27
|
-
"@canva/error": "^2.
|
|
27
|
+
"@canva/error": "^2.2.0",
|
|
28
28
|
"@canva/intents": "^2.0.0",
|
|
29
|
-
"@canva/platform": "^2.2.
|
|
29
|
+
"@canva/platform": "^2.2.1",
|
|
30
30
|
"@canva/user": "^2.1.2",
|
|
31
31
|
"react": "^19.2.3",
|
|
32
32
|
"react-dom": "^19.2.3",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { user } from "@canva/app-middleware/express";
|
|
1
2
|
import cors from "cors";
|
|
2
3
|
import express from "express";
|
|
3
4
|
import { createBaseServer } from "../utils/backend/base_backend/create";
|
|
4
|
-
import { createJwtMiddleware } from "../utils/backend/jwt_middleware/index";
|
|
5
5
|
import { createImageRouter } from "./routers/image";
|
|
6
6
|
|
|
7
7
|
async function main() {
|
|
@@ -50,8 +50,7 @@ async function main() {
|
|
|
50
50
|
* Initialize JWT middleware to verify Canva user tokens
|
|
51
51
|
* This middleware validates tokens sent from the frontend and extracts user information
|
|
52
52
|
*/
|
|
53
|
-
|
|
54
|
-
router.use(jwtMiddleware);
|
|
53
|
+
router.use(user.verifyToken({ appId: APP_ID }));
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* Add routes for image generation.
|
|
@@ -20,12 +20,13 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
22
22
|
"@canva/app-i18n-kit": "^1.2.0",
|
|
23
|
-
"@canva/app-
|
|
23
|
+
"@canva/app-middleware": "^0.0.0-beta.5",
|
|
24
|
+
"@canva/app-ui-kit": "^5.5.0",
|
|
24
25
|
"@canva/asset": "^2.3.0",
|
|
25
26
|
"@canva/design": "^2.7.5",
|
|
26
|
-
"@canva/error": "^2.
|
|
27
|
+
"@canva/error": "^2.2.0",
|
|
27
28
|
"@canva/intents": "^2.0.0",
|
|
28
|
-
"@canva/platform": "^2.2.
|
|
29
|
+
"@canva/platform": "^2.2.1",
|
|
29
30
|
"@canva/user": "^2.1.2",
|
|
30
31
|
"cookie-parser": "1.4.7",
|
|
31
32
|
"cors": "2.8.5",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import { TokenVerificationError } from "@canva/app-middleware";
|
|
2
3
|
import debug from "debug";
|
|
3
4
|
import express from "express";
|
|
4
5
|
import type { NextFunction, Request, Response } from "express";
|
|
@@ -63,6 +64,15 @@ export function createBaseServer(router: express.Router): BaseServer {
|
|
|
63
64
|
|
|
64
65
|
// default error handler
|
|
65
66
|
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
|
67
|
+
// Handle authentication errors from @canva/app-middleware
|
|
68
|
+
if (err instanceof TokenVerificationError) {
|
|
69
|
+
res.status(err.statusCode).json({
|
|
70
|
+
error: err.code,
|
|
71
|
+
message: err.message,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
66
76
|
console.error(err.stack);
|
|
67
77
|
res.status(500).send({
|
|
68
78
|
error: "something went wrong",
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
23
23
|
"@canva/app-i18n-kit": "^1.2.0",
|
|
24
|
-
"@canva/app-ui-kit": "^5.
|
|
24
|
+
"@canva/app-ui-kit": "^5.5.0",
|
|
25
25
|
"@canva/asset": "^2.3.0",
|
|
26
26
|
"@canva/design": "^2.7.5",
|
|
27
|
-
"@canva/error": "^2.
|
|
27
|
+
"@canva/error": "^2.2.0",
|
|
28
28
|
"@canva/intents": "^2.0.0",
|
|
29
|
-
"@canva/platform": "^2.2.
|
|
29
|
+
"@canva/platform": "^2.2.1",
|
|
30
30
|
"@canva/user": "^2.1.2",
|
|
31
31
|
"react": "^19.2.3",
|
|
32
32
|
"react-dom": "^19.2.3",
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@canva/app-hooks": "^0.0.0-beta.4",
|
|
25
25
|
"@canva/app-i18n-kit": "^1.2.0",
|
|
26
|
-
"@canva/app-ui-kit": "^5.
|
|
26
|
+
"@canva/app-ui-kit": "^5.5.0",
|
|
27
27
|
"@canva/asset": "^2.3.0",
|
|
28
28
|
"@canva/design": "^2.7.5",
|
|
29
|
-
"@canva/error": "^2.
|
|
29
|
+
"@canva/error": "^2.2.0",
|
|
30
30
|
"@canva/intents": "^2.0.0",
|
|
31
|
-
"@canva/platform": "^2.2.
|
|
31
|
+
"@canva/platform": "^2.2.1",
|
|
32
32
|
"@canva/user": "^2.1.2",
|
|
33
33
|
"@tanstack/react-query": "5.87.1",
|
|
34
34
|
"@types/react-infinite-scroller": "1.2.5",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createJwtMiddleware } from "./jwt_middleware";
|