Skip to content

Commit a234442

Browse files
authored
feat: Add helper functions for defining entries, settings, extension and api actions (#37)
1 parent 5731898 commit a234442

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+499
-314
lines changed

cli/incloud.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,30 @@ function parseArgs() {
3434
}
3535

3636
function makeMainFile(projectName: string) {
37-
const mainfile = `import { createInCloud } from "@inspatial/cloud";
37+
const mainfile =
38+
`import { createInCloud, defineExtension, defineEntry } from "@inspatial/cloud";
3839
39-
createInCloud({
40-
name: "${projectName}",
41-
description: "My InCloud Project",
42-
entryTypes: [], // Define your entry types here
43-
settingsTypes: [], // Define your settings types here
44-
actionGroups: [], // Define your API action groups here
40+
const myEntry = defineEntry("myEntry",{
41+
label: "My Entry",
42+
description: "A sample entry type",
43+
titleField: "name",
44+
fields: [{
45+
key: "name",
46+
type: "DataField",
47+
required: true,
48+
}]
4549
});
4650
51+
const myExtension = defineExtension("myExtension",{
52+
label: "My Extension",
53+
description: "A sample extension",
54+
entryTypes: [myEntry],
55+
settingsTypes: [],
56+
actionGroups: [],
57+
});
58+
59+
createInCloud("${projectName}", [myExtension]);
60+
4761
`;
4862
return mainfile;
4963
}

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@inspatial/cloud",
3-
"version": "0.7.2",
3+
"version": "0.7.3",
44
"license": "Apache-2.0",
55
"exports": {
66
".": "./mod.ts",

mod.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ export {
1818
ChildEntryList,
1919
ChildEntryType,
2020
} from "~/orm/child-entry/child-entry.ts";
21-
export { CloudAPIAction } from "~/api/cloud-action.ts";
22-
export { CloudAPIGroup } from "~/api/cloud-group.ts";
23-
export { CloudExtension } from "~/extension/cloud-extension.ts";
21+
export { CloudAPIAction, defineAPIAction } from "~/api/cloud-action.ts";
22+
export { CloudAPIGroup, defineAPIGroup } from "~/api/cloud-group.ts";
23+
export {
24+
CloudExtension,
25+
defineExtension,
26+
} from "~/extension/cloud-extension.ts";
2427

2528
export { MimeTypes };
26-
2729
export * from "~/orm/mod.ts";
2830

2931
export const utils = {

src/api/api-types.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { InField } from "~/orm/field/field-def-types.ts";
1+
import type { InField, InFieldType } from "~/orm/field/field-def-types.ts";
22
import type { InValue } from "~/orm/field/types.ts";
33

44
/**
@@ -62,16 +62,17 @@ export interface CloudAPIActionDocs {
6262
/**
6363
* A typed map of parameters passed to an action handler.
6464
*/
65-
export type CloudParam<P extends PropertyKey> = Omit<InField, "key"> & {
65+
export type CloudParam<
66+
P extends PropertyKey,
67+
> = {
6668
key: P;
67-
};
69+
} & InField;
6870
/**
6971
* A typed map of required parameters passed to an action handler.
7072
*/
7173

7274
export type ExtractParams<
73-
K extends PropertyKey,
74-
P extends Array<CloudParam<K>>,
75+
P extends Array<InField>,
7576
> =
7677
& {
7778
[S in P[number] as S["required"] extends true ? S["key"] : never]: InValue<

src/api/cloud-action.ts

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,35 @@ import type { SessionData } from "~/auth/types.ts";
99
import type { InCloud } from "~/in-cloud.ts";
1010

1111
export type ActionMethod<
12-
K extends PropertyKey = PropertyKey,
13-
P extends Array<CloudParam<K>> = Array<CloudParam<K>>,
14-
> = (args: {
12+
P extends Array<InField> | undefined = undefined,
13+
> = (
14+
args: P extends undefined ? ActionMethodNoParams : {
15+
inCloud: InCloud;
16+
orm: InSpatialORM;
17+
params: P extends Array<infer F> ? ExtractParams<P> : never;
18+
inRequest: InRequest;
19+
inResponse: InResponse;
20+
},
21+
) => Promise<any> | any;
22+
23+
type ActionMethodNoParams = {
1524
inCloud: InCloud;
1625
orm: InSpatialORM;
17-
params: ExtractParams<K, P>;
1826
inRequest: InRequest;
1927
inResponse: InResponse;
20-
}) => Promise<any> | any;
21-
22-
export type ActionConfig<
23-
K extends PropertyKey = PropertyKey,
24-
P extends Array<CloudParam<K>> = Array<CloudParam<K>>,
25-
R extends ActionMethod<K, P> = ActionMethod<K, P>,
26-
> = {
27-
run: R;
28-
/**
29-
* Whether to skip reading the request body. Should be set to true if the action
30-
* will be reading the request body itself, such as when uploading files.
31-
*/
32-
raw?: boolean;
33-
description?: string;
28+
};
29+
30+
export interface ActionConfigBase {
3431
label?: string;
32+
description?: string;
33+
raw?: boolean;
3534
authRequired?: boolean;
3635
hideFromApi?: boolean;
37-
params: P;
38-
};
36+
}
37+
3938
export class CloudAPIAction<
40-
K extends PropertyKey = PropertyKey,
41-
P extends Array<CloudParam<K>> = Array<CloudParam<K>>,
42-
R extends ActionMethod<K, P> = ActionMethod<K, P>,
39+
K extends string = string,
40+
AP extends Array<InField & { key: K }> | undefined = any,
4341
> {
4442
description: string = "This is a Cloud API action";
4543
label?: string;
@@ -52,23 +50,20 @@ export class CloudAPIAction<
5250
params: Map<string, CloudParam<PropertyKey>>;
5351
requiredParams: string[] = [];
5452

55-
#_run: (args: {
56-
inCloud: InCloud;
57-
orm: InSpatialORM;
58-
params: any;
59-
inRequest: InRequest;
60-
inResponse: InResponse;
61-
}) => Promise<any> | any;
53+
#_run: ActionMethod<AP>;
6254

6355
raiseError(message: string): never {
6456
raiseServerException(400, message);
6557
}
6658

6759
constructor(
6860
actionName: string,
69-
config: ActionConfig<K, P, R>,
61+
config: ActionConfigBase & {
62+
params?: AP extends undefined ? never : AP;
63+
action: ActionMethod<AP>;
64+
},
7065
) {
71-
this.#_run = config.run;
66+
this.#_run = config.action;
7267
this.actionName = actionName;
7368
this.raw = config.raw || false;
7469
this.label = config.label || this.label ||
@@ -80,10 +75,10 @@ export class CloudAPIAction<
8075
if (config.hideFromApi === true) {
8176
this.includeInAPI = false;
8277
}
83-
this.params = new Map(config.params.map((p) => [p.key as string, p]));
84-
this.requiredParams = config.params.filter((param) => param.required).map(
78+
this.params = new Map(config.params?.map((p) => [p.key as string, p]));
79+
this.requiredParams = config.params?.filter((param) => param.required).map(
8580
(p) => p.key as string,
86-
);
81+
) || [];
8782
}
8883

8984
#validateParams(
@@ -186,6 +181,25 @@ export class CloudAPIAction<
186181
runObject.orm = args.inCloud.orm.withUser(user);
187182
}
188183

189-
return await this.#_run(runObject);
184+
return await this.#_run(runObject as any);
190185
}
191186
}
187+
188+
/** Define a Cloud API Action
189+
*
190+
* @param actionName The name of the action
191+
* @param config The configuration for the action
192+
* @returns A new CloudAPIAction instance
193+
*/
194+
export function defineAPIAction<
195+
K extends string,
196+
AP extends Array<InField & { key: K }> | undefined,
197+
>(
198+
actionName: string,
199+
config: ActionConfigBase & {
200+
params?: AP extends undefined ? never : AP;
201+
action: ActionMethod<AP>;
202+
},
203+
): CloudAPIAction<K, AP> {
204+
return new CloudAPIAction(actionName, config);
205+
}

src/api/cloud-api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export class CloudAPI {
100100
label: "Get Docs",
101101
description: "Get API documentation",
102102
params: [],
103-
run({ inCloud, inRequest }) {
103+
action({ inCloud, inRequest }) {
104104
const user = inRequest.context.get<SessionData>("user");
105105
if (!user) {
106106
return;
@@ -142,7 +142,7 @@ export class CloudAPI {
142142
description: "Ping the server",
143143
authRequired: false,
144144
params: [],
145-
run({ inCloud }) {
145+
action({ inCloud }) {
146146
return {
147147
message: "pong",
148148
timestamp: Date.now(),

src/api/cloud-group.ts

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {
2-
type ActionConfig,
2+
type ActionConfigBase,
33
type ActionMethod,
44
CloudAPIAction,
55
} from "~/api/cloud-action.ts";
6-
import type { CloudParam } from "~/api/api-types.ts";
76
import { raiseServerException } from "~/serve/server-exception.ts";
7+
import convertString from "../utils/convert-string.ts";
8+
import type { InField } from "../orm/field/field-def-types.ts";
89

910
export class CloudAPIGroup<
1011
G extends string = string,
@@ -23,7 +24,7 @@ export class CloudAPIGroup<
2324
this.description = config.description;
2425
this.label = config.label;
2526
this.actions = new Map();
26-
config.actions?.forEach((action) => this.addAction(action));
27+
config.actions?.forEach((action) => this.#addAction(action));
2728
}
2829
#addAction(action: CloudAPIAction) {
2930
if (this.actions.has(action.actionName)) {
@@ -35,31 +36,41 @@ export class CloudAPIGroup<
3536
action.groupName = this.groupName;
3637
this.actions.set(action.actionName, action);
3738
}
39+
/** Add a new action to the group
40+
*
41+
* @param actionName The name of the action
42+
* @param config The configuration for the action
43+
*/
3844
addAction<
39-
K extends PropertyKey = PropertyKey,
40-
P extends Array<CloudParam<K>> = Array<CloudParam<K>>,
41-
R extends ActionMethod<K, P> = ActionMethod<K, P>,
42-
>(name: string, config: ActionConfig<K, P, R>): void;
43-
addAction(action: CloudAPIAction): void;
44-
addAction(
45-
nameOrAction: string | CloudAPIAction,
46-
actionConfig?: ActionConfig,
45+
K extends string,
46+
AP extends Array<InField & { key: K }> | undefined,
47+
>(
48+
actionName: string,
49+
config: ActionConfigBase & {
50+
params?: AP extends undefined ? never : AP;
51+
action: ActionMethod<AP>;
52+
},
4753
): void {
48-
if (nameOrAction instanceof CloudAPIAction) {
49-
this.#addAction(nameOrAction);
50-
return;
51-
}
52-
if (typeof nameOrAction !== "string") {
53-
raiseServerException(400, "action name must be a string");
54-
}
55-
if (actionConfig === undefined) {
56-
raiseServerException(
57-
400,
58-
`Please provide config options for ${nameOrAction} action`,
59-
);
60-
}
61-
62-
const action = new CloudAPIAction(nameOrAction, actionConfig);
54+
const action = new CloudAPIAction(actionName, config);
6355
this.#addAction(action);
6456
}
6557
}
58+
59+
/** Define a new API group
60+
*
61+
* @param groupName The name of the group
62+
* @param config The configuration for the group
63+
* @returns The defined API group
64+
*/
65+
export function defineAPIGroup<G extends string>(groupName: G, config?: {
66+
description?: string;
67+
label?: string;
68+
actions?: Array<CloudAPIAction<any, any>>;
69+
}): CloudAPIGroup<G> {
70+
const group = new CloudAPIGroup(groupName, {
71+
description: config?.description || "",
72+
label: config?.label || convertString(groupName, "title", true),
73+
actions: config?.actions,
74+
});
75+
return group;
76+
}

src/auth/actions/auth-check.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { CloudAPIAction } from "~/api/cloud-action.ts";
22

33
const authCheck = new CloudAPIAction("authCheck", {
44
description: "Check if user is authenticated",
5-
run({ inRequest }) {
5+
action({ inRequest }) {
66
const user = inRequest.context.get("user");
77

88
return user;

src/auth/actions/get-account.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { SessionData } from "../types.ts";
33

44
export const getAccount = new CloudAPIAction("getAccount", {
55
description: "Gets the account for the current authenticated user",
6-
async run({ inRequest, inCloud }) {
6+
async action({ inRequest, inCloud }) {
77
const user = inRequest.context.get<SessionData>("user");
88
if (!user || !user.accountId) {
99
return;

src/auth/actions/google/google-auth-callback.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { handleGoogleSignup } from "./handle-google-signup.ts";
88
const googleAuthCallback = new CloudAPIAction("googleAuthCallback", {
99
authRequired: false,
1010
description: "Google OAuth2 callback",
11-
async run({ inCloud, orm, inRequest, inResponse, params }) {
11+
async action({ inCloud, orm, inRequest, inResponse, params }) {
1212
const { code, state } = params;
1313
const authSettings = await orm.getSettings(
1414
"authSettings",

0 commit comments

Comments
 (0)