create-ultimabase 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # create-ultimabase
2
+
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - The published starter starts: `ultimabase dev` runs `dist/serve.js`, and `@ultimabase/realtime`, which `@ultimabase/graphql` and `@ultimabase/rest` import, is a required peer the starter lists.
8
+
9
+ ## 0.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 0e885c4: The first release: the kernel, its adapters, transports and plugins, the testing helpers and the starter.
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
- # Temporary Holding Version
1
+ # create-ultimabase
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Writes a new UltimaBase application, ready to start: its models, a test and its server. Run it with `npm create ultimabase`.
4
+
5
+ Documentation: [Quickstart](https://ultimabase.dev/docs/quickstart).
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ // The `create-ultimabase` bin (D-130).
3
+ import { main, processIo } from './main.js';
4
+ process.exitCode = await main(process.argv.slice(2), processIo());
package/dist/main.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export type Io = {
2
+ readonly cwd: string;
3
+ /** `npm_config_user_agent`, which names the package manager that ran it. */
4
+ readonly userAgent: string | undefined;
5
+ /** Asks in a terminal; `undefined` elsewhere. */
6
+ readonly ask: ((question: string) => Promise<string>) | undefined;
7
+ readonly print: (text: string) => void;
8
+ readonly fail: (text: string) => void;
9
+ };
10
+ /** A question asked on `input` and `output`, a terminal. */
11
+ export declare const terminal: (input: NodeJS.ReadableStream, output: NodeJS.WritableStream) => (question: string) => Promise<string>;
12
+ /** The process's directory, package manager, terminal and output. */
13
+ export declare function processIo(): Io;
14
+ /** Writes the starter; the process's exit code. */
15
+ export declare function main(args: readonly string[], io: Io): Promise<number>;
16
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,EAAE,GAAG;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IACjE,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACrC,CAAA;AAmBD,4DAA4D;AAC5D,eAAO,MAAM,QAAQ,UACZ,MAAM,CAAC,cAAc,UAAU,MAAM,CAAC,cAAc,gBAC3C,MAAM,KAAG,OAAO,CAAC,MAAM,CAOvC,CAAA;AAEF,qEAAqE;AACrE,wBAAgB,SAAS,IAAI,EAAE,CAa9B;AAYD,mDAAmD;AACnD,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B3E"}
package/dist/main.js ADDED
@@ -0,0 +1,79 @@
1
+ // `npm create ultimabase [directory]` (D-130): writes the starter in an empty
2
+ // directory, installs nothing, and prints the next commands.
3
+ import { existsSync, readdirSync, statSync } from 'node:fs';
4
+ import { createInterface } from 'node:readline/promises';
5
+ import { basename, relative, resolve } from 'node:path';
6
+ import { write } from './starter.js';
7
+ const usage = 'Usage: npm create ultimabase [directory]';
8
+ const fallback = 'my-app';
9
+ /** npm's rule for a new package's name. */
10
+ const named = (name) => name.length <= 214 && /^[a-z0-9~-][a-z0-9._~-]*$/u.test(name);
11
+ const managerOf = (userAgent) => {
12
+ const name = userAgent?.split('/')[0];
13
+ return name === 'yarn' || name === 'pnpm' ? name : 'npm';
14
+ };
15
+ const steps = {
16
+ npm: ['npm install', 'npm run dev'],
17
+ yarn: ['yarn', 'yarn dev'],
18
+ pnpm: ['pnpm install', 'pnpm dev'],
19
+ };
20
+ /** A question asked on `input` and `output`, a terminal. */
21
+ export const terminal = (input, output) => async (question) => {
22
+ const line = createInterface({ input, output });
23
+ try {
24
+ return await line.question(question);
25
+ }
26
+ finally {
27
+ line.close();
28
+ }
29
+ };
30
+ /** The process's directory, package manager, terminal and output. */
31
+ export function processIo() {
32
+ const tty = process.stdin.isTTY && process.stdout.isTTY;
33
+ return {
34
+ cwd: process.cwd(),
35
+ userAgent: process.env['npm_config_user_agent'],
36
+ ask: tty ? terminal(process.stdin, process.stdout) : undefined,
37
+ print: (text) => {
38
+ console.log(text);
39
+ },
40
+ fail: (text) => {
41
+ console.error(text);
42
+ },
43
+ };
44
+ }
45
+ async function directoryOf(io) {
46
+ if (io.ask === undefined)
47
+ return fallback;
48
+ const answer = (await io.ask(`? Project name: (${fallback}) `)).trim();
49
+ return answer === '' ? fallback : answer;
50
+ }
51
+ const empty = (target) => !existsSync(target) ||
52
+ (statSync(target).isDirectory() && readdirSync(target).length === 0);
53
+ /** Writes the starter; the process's exit code. */
54
+ export async function main(args, io) {
55
+ const [given, ...more] = args;
56
+ if (more.length > 0 || given?.startsWith('-') === true) {
57
+ io.fail(usage);
58
+ return 1;
59
+ }
60
+ const directory = given ?? (await directoryOf(io));
61
+ const target = resolve(io.cwd, directory);
62
+ const name = basename(target);
63
+ if (!named(name)) {
64
+ io.fail(`${name} cannot name a package: use lowercase letters, digits, '-', '.' and '_'.`);
65
+ return 1;
66
+ }
67
+ if (!empty(target)) {
68
+ io.fail(`${directory} is not an empty directory.`);
69
+ return 1;
70
+ }
71
+ const manager = managerOf(io.userAgent);
72
+ write(target, name, manager);
73
+ const cd = relative(io.cwd, target) === ''
74
+ ? []
75
+ : [`cd ${/\s/u.test(directory) ? `"${directory}"` : directory}`];
76
+ const next = [...cd, ...steps[manager]].map((step) => ` ${step}`);
77
+ io.print(`\nCreated ${name}. Next:\n\n${next.join('\n')}\n`);
78
+ return 0;
79
+ }
@@ -0,0 +1,13 @@
1
+ export type Manager = 'npm' | 'yarn' | 'pnpm';
2
+ /** The packages the starter runs beside UltimaBase's, as the repository tests them. */
3
+ export declare const others: {
4
+ readonly '@types/node': '^24.19.2';
5
+ readonly graphql: '^17.0.2';
6
+ readonly vite: '^8.3.4';
7
+ readonly vitest: '^5.0.5';
8
+ };
9
+ /** `create-ultimabase`'s version, which the official packages share (D-60). */
10
+ export declare function ownVersion(): string;
11
+ /** Writes the starter named `name` in `target`, an empty or missing directory. */
12
+ export declare function write(target: string, name: string, manager: Manager): void;
13
+ //# sourceMappingURL=starter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"starter.d.ts","sourceRoot":"","sources":["../src/starter.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAI7C,uFAAuF;AACvF,eAAO,MAAM,MAAM;aAClB,aAAa,EAAE,UAAU;aACzB,OAAO,EAAE,SAAS;aAClB,IAAI,EAAE,QAAQ;aACd,MAAM,EAAE,QAAQ;CACP,CAAA;AAEV,+EAA+E;AAC/E,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAiDD,kFAAkF;AAClF,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAS1E"}
@@ -0,0 +1,69 @@
1
+ // The starter's files (D-130): the template as it is, its `gitignore` as
2
+ // `.gitignore`, and the package.json and README that name the application.
3
+ import { cpSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ const template = fileURLToPath(new URL('../template', import.meta.url));
7
+ /** The packages the starter runs beside UltimaBase's, as the repository tests them. */
8
+ export const others = {
9
+ '@types/node': '^24.19.2',
10
+ graphql: '^17.0.2',
11
+ vite: '^8.3.4',
12
+ vitest: '^5.0.5',
13
+ };
14
+ /** `create-ultimabase`'s version, which the official packages share (D-60). */
15
+ export function ownVersion() {
16
+ const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
17
+ return String(Reflect.get(Object(manifest), 'version'));
18
+ }
19
+ const manifestOf = (name) => {
20
+ const ours = `^${ownVersion()}`;
21
+ return {
22
+ name,
23
+ private: true,
24
+ type: 'module',
25
+ engines: { node: '>=24.7.0' },
26
+ scripts: {
27
+ dev: 'ultimabase dev',
28
+ start: 'ultimabase start',
29
+ test: 'vitest',
30
+ },
31
+ dependencies: {
32
+ '@ultimabase/graphql': ours,
33
+ '@ultimabase/http': ours,
34
+ '@ultimabase/realtime': ours,
35
+ graphql: others.graphql,
36
+ ultimabase: ours,
37
+ },
38
+ devDependencies: {
39
+ '@types/node': others['@types/node'],
40
+ '@ultimabase/testing': ours,
41
+ vite: others.vite,
42
+ vitest: others.vitest,
43
+ },
44
+ };
45
+ };
46
+ /** How `manager` runs a script other than `start` and `test`. */
47
+ const run = (manager) => manager === 'npm' ? 'npm run' : manager;
48
+ const readme = (name, manager) => `# ${name}
49
+
50
+ An UltimaBase application. Node runs its TypeScript as it is written.
51
+
52
+ - \`${run(manager)} dev\` serves it on http://localhost:3000, GraphQL on
53
+ \`/graphql\`, and restarts it when a file changes; \`PORT\` sets another
54
+ port.
55
+ - \`${manager} start\` serves it in production.
56
+ - \`${manager} test\` runs its tests, each on a new in-memory database.
57
+
58
+ \`src/models.ts\` declares the models, \`src/app.ts\` the database and the
59
+ plugins, and \`ultimabase.config.ts\` names the application the
60
+ \`ultimabase\` command runs.
61
+ `;
62
+ /** Writes the starter named `name` in `target`, an empty or missing directory. */
63
+ export function write(target, name, manager) {
64
+ mkdirSync(target, { recursive: true });
65
+ cpSync(template, target, { recursive: true });
66
+ renameSync(join(target, 'gitignore'), join(target, '.gitignore'));
67
+ writeFileSync(join(target, 'package.json'), `${JSON.stringify(manifestOf(name), undefined, '\t')}\n`);
68
+ writeFileSync(join(target, 'README.md'), readme(name, manager));
69
+ }
package/package.json CHANGED
@@ -1,6 +1,40 @@
1
1
  {
2
2
  "name": "create-ultimabase",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "description": "Writes a new UltimaBase application: npm create ultimabase.",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://ultimabase.dev/docs/quickstart",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/MrEkinox/ultimabase.git",
11
+ "directory": "packages/create-ultimabase"
12
+ },
13
+ "engines": {
14
+ "node": ">=24.7.0"
15
+ },
16
+ "bin": "./dist/cli.js",
17
+ "files": [
18
+ "dist",
19
+ "src",
20
+ "template",
21
+ "!src/**/*.test.ts",
22
+ "!src/test"
23
+ ],
24
+ "scripts": {
25
+ "prepack": "rm -rf dist && yarn run -T tsc --project tsconfig.build.json"
26
+ },
27
+ "publishConfig": {
28
+ "bin": "./dist/cli.js"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "24.19.2",
32
+ "@ultimabase/graphql": "0.1.1",
33
+ "@ultimabase/http": "0.1.1",
34
+ "@ultimabase/testing": "0.1.1",
35
+ "graphql": "17.0.2",
36
+ "ultimabase": "0.1.1",
37
+ "vite": "8.3.4",
38
+ "vitest": "5.0.5"
39
+ }
6
40
  }
package/src/cli.ts ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // The `create-ultimabase` bin (D-130).
3
+ import { main, processIo } from './main.ts'
4
+
5
+ process.exitCode = await main(process.argv.slice(2), processIo())
package/src/main.ts ADDED
@@ -0,0 +1,103 @@
1
+ // `npm create ultimabase [directory]` (D-130): writes the starter in an empty
2
+ // directory, installs nothing, and prints the next commands.
3
+ import { existsSync, readdirSync, statSync } from 'node:fs'
4
+ import { createInterface } from 'node:readline/promises'
5
+ import { basename, relative, resolve } from 'node:path'
6
+ import type { Manager } from './starter.ts'
7
+ import { write } from './starter.ts'
8
+
9
+ export type Io = {
10
+ readonly cwd: string
11
+ /** `npm_config_user_agent`, which names the package manager that ran it. */
12
+ readonly userAgent: string | undefined
13
+ /** Asks in a terminal; `undefined` elsewhere. */
14
+ readonly ask: ((question: string) => Promise<string>) | undefined
15
+ readonly print: (text: string) => void
16
+ readonly fail: (text: string) => void
17
+ }
18
+
19
+ const usage = 'Usage: npm create ultimabase [directory]'
20
+ const fallback = 'my-app'
21
+
22
+ /** npm's rule for a new package's name. */
23
+ const named = (name: string): boolean =>
24
+ name.length <= 214 && /^[a-z0-9~-][a-z0-9._~-]*$/u.test(name)
25
+
26
+ const managerOf = (userAgent: string | undefined): Manager => {
27
+ const name = userAgent?.split('/')[0]
28
+ return name === 'yarn' || name === 'pnpm' ? name : 'npm'
29
+ }
30
+ const steps: Record<Manager, readonly string[]> = {
31
+ npm: ['npm install', 'npm run dev'],
32
+ yarn: ['yarn', 'yarn dev'],
33
+ pnpm: ['pnpm install', 'pnpm dev'],
34
+ }
35
+
36
+ /** A question asked on `input` and `output`, a terminal. */
37
+ export const terminal =
38
+ (input: NodeJS.ReadableStream, output: NodeJS.WritableStream) =>
39
+ async (question: string): Promise<string> => {
40
+ const line = createInterface({ input, output })
41
+ try {
42
+ return await line.question(question)
43
+ } finally {
44
+ line.close()
45
+ }
46
+ }
47
+
48
+ /** The process's directory, package manager, terminal and output. */
49
+ export function processIo(): Io {
50
+ const tty = process.stdin.isTTY && process.stdout.isTTY
51
+ return {
52
+ cwd: process.cwd(),
53
+ userAgent: process.env['npm_config_user_agent'],
54
+ ask: tty ? terminal(process.stdin, process.stdout) : undefined,
55
+ print: (text) => {
56
+ console.log(text)
57
+ },
58
+ fail: (text) => {
59
+ console.error(text)
60
+ },
61
+ }
62
+ }
63
+
64
+ async function directoryOf(io: Io): Promise<string> {
65
+ if (io.ask === undefined) return fallback
66
+ const answer = (await io.ask(`? Project name: (${fallback}) `)).trim()
67
+ return answer === '' ? fallback : answer
68
+ }
69
+
70
+ const empty = (target: string): boolean =>
71
+ !existsSync(target) ||
72
+ (statSync(target).isDirectory() && readdirSync(target).length === 0)
73
+
74
+ /** Writes the starter; the process's exit code. */
75
+ export async function main(args: readonly string[], io: Io): Promise<number> {
76
+ const [given, ...more] = args
77
+ if (more.length > 0 || given?.startsWith('-') === true) {
78
+ io.fail(usage)
79
+ return 1
80
+ }
81
+ const directory = given ?? (await directoryOf(io))
82
+ const target = resolve(io.cwd, directory)
83
+ const name = basename(target)
84
+ if (!named(name)) {
85
+ io.fail(
86
+ `${name} cannot name a package: use lowercase letters, digits, '-', '.' and '_'.`,
87
+ )
88
+ return 1
89
+ }
90
+ if (!empty(target)) {
91
+ io.fail(`${directory} is not an empty directory.`)
92
+ return 1
93
+ }
94
+ const manager = managerOf(io.userAgent)
95
+ write(target, name, manager)
96
+ const cd =
97
+ relative(io.cwd, target) === ''
98
+ ? []
99
+ : [`cd ${/\s/u.test(directory) ? `"${directory}"` : directory}`]
100
+ const next = [...cd, ...steps[manager]].map((step) => ` ${step}`)
101
+ io.print(`\nCreated ${name}. Next:\n\n${next.join('\n')}\n`)
102
+ return 0
103
+ }
package/src/starter.ts ADDED
@@ -0,0 +1,90 @@
1
+ // The starter's files (D-130): the template as it is, its `gitignore` as
2
+ // `.gitignore`, and the package.json and README that name the application.
3
+ import {
4
+ cpSync,
5
+ mkdirSync,
6
+ readFileSync,
7
+ renameSync,
8
+ writeFileSync,
9
+ } from 'node:fs'
10
+ import { join } from 'node:path'
11
+ import { fileURLToPath } from 'node:url'
12
+
13
+ export type Manager = 'npm' | 'yarn' | 'pnpm'
14
+
15
+ const template = fileURLToPath(new URL('../template', import.meta.url))
16
+
17
+ /** The packages the starter runs beside UltimaBase's, as the repository tests them. */
18
+ export const others = {
19
+ '@types/node': '^24.19.2',
20
+ graphql: '^17.0.2',
21
+ vite: '^8.3.4',
22
+ vitest: '^5.0.5',
23
+ } as const
24
+
25
+ /** `create-ultimabase`'s version, which the official packages share (D-60). */
26
+ export function ownVersion(): string {
27
+ const manifest: unknown = JSON.parse(
28
+ readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
29
+ )
30
+ return String(Reflect.get(Object(manifest), 'version'))
31
+ }
32
+
33
+ const manifestOf = (name: string): object => {
34
+ const ours = `^${ownVersion()}`
35
+ return {
36
+ name,
37
+ private: true,
38
+ type: 'module',
39
+ engines: { node: '>=24.7.0' },
40
+ scripts: {
41
+ dev: 'ultimabase dev',
42
+ start: 'ultimabase start',
43
+ test: 'vitest',
44
+ },
45
+ dependencies: {
46
+ '@ultimabase/graphql': ours,
47
+ '@ultimabase/http': ours,
48
+ '@ultimabase/realtime': ours,
49
+ graphql: others.graphql,
50
+ ultimabase: ours,
51
+ },
52
+ devDependencies: {
53
+ '@types/node': others['@types/node'],
54
+ '@ultimabase/testing': ours,
55
+ vite: others.vite,
56
+ vitest: others.vitest,
57
+ },
58
+ }
59
+ }
60
+
61
+ /** How `manager` runs a script other than `start` and `test`. */
62
+ const run = (manager: Manager): string =>
63
+ manager === 'npm' ? 'npm run' : manager
64
+
65
+ const readme = (name: string, manager: Manager): string => `# ${name}
66
+
67
+ An UltimaBase application. Node runs its TypeScript as it is written.
68
+
69
+ - \`${run(manager)} dev\` serves it on http://localhost:3000, GraphQL on
70
+ \`/graphql\`, and restarts it when a file changes; \`PORT\` sets another
71
+ port.
72
+ - \`${manager} start\` serves it in production.
73
+ - \`${manager} test\` runs its tests, each on a new in-memory database.
74
+
75
+ \`src/models.ts\` declares the models, \`src/app.ts\` the database and the
76
+ plugins, and \`ultimabase.config.ts\` names the application the
77
+ \`ultimabase\` command runs.
78
+ `
79
+
80
+ /** Writes the starter named `name` in `target`, an empty or missing directory. */
81
+ export function write(target: string, name: string, manager: Manager): void {
82
+ mkdirSync(target, { recursive: true })
83
+ cpSync(template, target, { recursive: true })
84
+ renameSync(join(target, 'gitignore'), join(target, '.gitignore'))
85
+ writeFileSync(
86
+ join(target, 'package.json'),
87
+ `${JSON.stringify(manifestOf(name), undefined, '\t')}\n`,
88
+ )
89
+ writeFileSync(join(target, 'README.md'), readme(name, manager))
90
+ }
@@ -0,0 +1 @@
1
+ node_modules
@@ -0,0 +1,20 @@
1
+ // Each test runs the application on a new in-memory database and a free port.
2
+ import { testApplication } from '@ultimabase/testing'
3
+ import { master } from 'ultimabase'
4
+ import { expect, it } from 'vitest'
5
+ import { app } from './app.ts'
6
+ import { Post } from './models.ts'
7
+
8
+ const running = testApplication(app)
9
+
10
+ it('lists the posts over GraphQL', async () => {
11
+ await Post.create({ data: { title: 'Hello' } }, { as: master })
12
+ const response = await fetch(`${running.url}/graphql`, {
13
+ method: 'POST',
14
+ headers: { 'content-type': 'application/json' },
15
+ body: JSON.stringify({ query: '{ posts { edges { node { title } } } }' }),
16
+ })
17
+ expect(await response.json()).toEqual({
18
+ data: { posts: { edges: [{ node: { title: 'Hello' } }] } },
19
+ })
20
+ })
@@ -0,0 +1,16 @@
1
+ // The application: its database, its plugins and its models.
2
+ import { graphqlPlugin } from '@ultimabase/graphql'
3
+ import { httpPlugin } from '@ultimabase/http'
4
+ import { defineApp, memory } from 'ultimabase'
5
+ import { Post } from './models.ts'
6
+
7
+ export const app = defineApp({
8
+ // For PostgreSQL: postgres({ url: process.env['DATABASE_URL'] }) from @ultimabase/postgres.
9
+ database: memory(),
10
+ plugins: [
11
+ httpPlugin(),
12
+ graphqlPlugin(),
13
+ // For REST too: restPlugin() from @ultimabase/rest.
14
+ ],
15
+ models: [Post],
16
+ })
@@ -0,0 +1,11 @@
1
+ // The application's models: each one a table, its fields and who may
2
+ // read and write it.
3
+ import { allow, defineModel } from 'ultimabase'
4
+
5
+ export const Post = defineModel({
6
+ name: 'Post',
7
+ fields: (f) => ({
8
+ title: f.string(),
9
+ }),
10
+ // Anyone may read and write posts; see `allow` for the other rules.
11
+ }).with({ access: allow.public })
@@ -0,0 +1,17 @@
1
+ {
2
+ // For the editor: Node runs the TypeScript as it is written.
3
+ "compilerOptions": {
4
+ "target": "ES2024",
5
+ "module": "NodeNext",
6
+ "strict": true,
7
+ "exactOptionalPropertyTypes": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "verbatimModuleSyntax": true,
10
+ "erasableSyntaxOnly": true,
11
+ "allowImportingTsExtensions": true,
12
+ "noEmit": true,
13
+ "skipLibCheck": true,
14
+ "types": ["node"]
15
+ },
16
+ "include": ["src", "ultimabase.config.ts"]
17
+ }
@@ -0,0 +1,2 @@
1
+ // What `ultimabase dev` and `ultimabase start` run: the application.
2
+ export { app as default } from './src/app.ts'