@fragno-dev/create 0.0.3 → 0.1.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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -3
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/index.ts +13 -2
- package/src/integration.test.ts +17 -8
- package/src/package-json.ts +28 -1
- package/src/utils.ts +6 -2
- package/templates/fragment/package.template.json +10 -15
- package/templates/fragment/src/client/solid.ts +7 -0
- package/templates/fragment/src/index.ts +2 -2
- package/templates/optional/agent/AGENTS.md +89 -0
- package/templates/optional/builder/tsdown.config.ts +1 -0
- package/templates/optional/database/index.ts +141 -0
- package/templates/optional/database/schema.ts +12 -0
- package/.turbo/turbo-test.log +0 -66
- package/.turbo/turbo-types$colon$check.log +0 -1
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { copy, merge } from "./utils.ts";
|
|
5
|
-
import { buildToolPkg } from "./package-json.ts";
|
|
5
|
+
import { basePkg, buildToolPkg, databasePkg } from "./package-json.ts";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
const templateTypesSchema = z.literal("fragment");
|
|
@@ -28,16 +28,22 @@ export const createOptionsSchema = z.object({
|
|
|
28
28
|
name: z.string(),
|
|
29
29
|
template: templateTypesSchema,
|
|
30
30
|
agentDocs: agentDocsSchema,
|
|
31
|
+
withDatabase: z.boolean(),
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
type CreateOptions = z.infer<typeof createOptionsSchema>;
|
|
34
35
|
|
|
35
36
|
export function create(options: CreateOptions) {
|
|
36
|
-
let pkgOverride: Record<string, unknown> = { name: options.name };
|
|
37
|
+
let pkgOverride: Record<string, unknown> = merge(basePkg, { name: options.name });
|
|
37
38
|
|
|
38
39
|
// Build tool pkg overrides
|
|
39
40
|
pkgOverride = merge(pkgOverride, buildToolPkg[options.buildTool]);
|
|
40
41
|
|
|
42
|
+
// Database pkg overrides
|
|
43
|
+
if (options.withDatabase) {
|
|
44
|
+
pkgOverride = merge(pkgOverride, databasePkg);
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
if (options.template == "fragment") {
|
|
42
48
|
writeFragmentTemplate(options.path, pkgOverride);
|
|
43
49
|
} else {
|
|
@@ -77,6 +83,11 @@ export function create(options: CreateOptions) {
|
|
|
77
83
|
case "none":
|
|
78
84
|
break;
|
|
79
85
|
}
|
|
86
|
+
|
|
87
|
+
if (options.withDatabase) {
|
|
88
|
+
writeOptionalTemplate(options.path, "database/index.ts", "src/index.ts");
|
|
89
|
+
writeOptionalTemplate(options.path, "database/schema.ts", "src/schema.ts");
|
|
90
|
+
}
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
function getTemplateDir(): string {
|
package/src/integration.test.ts
CHANGED
|
@@ -19,9 +19,10 @@ async function createTempDir(name: string): Promise<string> {
|
|
|
19
19
|
return dir;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
type BuildTool = "tsdown" | "esbuild" | "vite" | "rollup" | "webpack" | "rspack";
|
|
23
|
+
|
|
24
|
+
function createFragmentTestSuite(buildTool: BuildTool, withDatabase: boolean) {
|
|
25
|
+
return () => {
|
|
25
26
|
let tempDir: string;
|
|
26
27
|
const testConfig = {
|
|
27
28
|
name: "@myorg/test",
|
|
@@ -31,16 +32,17 @@ describe.concurrent.each(["tsdown", "esbuild", "vite", "rollup", "webpack", "rsp
|
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
beforeAll(async () => {
|
|
34
|
-
|
|
35
|
+
const suffix = withDatabase ? "db" : "no-db";
|
|
36
|
+
tempDir = await createTempDir(`fragment-test-${buildTool}-${suffix}`);
|
|
35
37
|
console.log("temp", tempDir);
|
|
36
|
-
create({ ...testConfig, path: tempDir });
|
|
38
|
+
create({ ...testConfig, path: tempDir, withDatabase });
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
afterAll(async () => {
|
|
40
42
|
await fs.rm(tempDir, { recursive: true });
|
|
41
43
|
});
|
|
42
44
|
|
|
43
|
-
describe.sequential(
|
|
45
|
+
describe.sequential(buildTool, () => {
|
|
44
46
|
test("package.json correctly templated", async () => {
|
|
45
47
|
const pkg = path.join(tempDir, "package.json");
|
|
46
48
|
const pkgContent = await fs.readFile(pkg, "utf8");
|
|
@@ -74,7 +76,7 @@ describe.concurrent.each(["tsdown", "esbuild", "vite", "rollup", "webpack", "rsp
|
|
|
74
76
|
but somehow when running through vitest the module resolution mechanism changes causing
|
|
75
77
|
the build to fail.
|
|
76
78
|
*/
|
|
77
|
-
test.skipIf(buildTool
|
|
79
|
+
test.skipIf(buildTool === "rollup")("builds", { timeout: 40000 }, async () => {
|
|
78
80
|
const result = await execAsync("bun run build", {
|
|
79
81
|
cwd: tempDir,
|
|
80
82
|
encoding: "utf8",
|
|
@@ -99,5 +101,12 @@ describe.concurrent.each(["tsdown", "esbuild", "vite", "rollup", "webpack", "rsp
|
|
|
99
101
|
}
|
|
100
102
|
});
|
|
101
103
|
});
|
|
102
|
-
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
describe.concurrent.each(["tsdown", "esbuild", "vite", "rollup", "webpack", "rspack"] as const)(
|
|
108
|
+
"fragment with %s (with database)",
|
|
109
|
+
(buildTool) => createFragmentTestSuite(buildTool, true)(),
|
|
103
110
|
);
|
|
111
|
+
|
|
112
|
+
describe("fragment with tsdown (without database)", createFragmentTestSuite("tsdown", false));
|
package/src/package-json.ts
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import type { BuildTools } from "./index";
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const fragnoCoreVersion = "^0.1.1";
|
|
4
|
+
const fragnoDbVersion = "^0.1.1";
|
|
5
|
+
const unpluginFragnoVersion = "^0.0.2";
|
|
6
|
+
const fragnoCliVersion = "^0.1.2";
|
|
7
|
+
|
|
8
|
+
export const basePkg: Record<string, unknown> = {
|
|
9
|
+
dependencies: {
|
|
10
|
+
"@fragno-dev/core": fragnoCoreVersion,
|
|
11
|
+
zod: "^4.0.5",
|
|
12
|
+
},
|
|
13
|
+
devDependencies: {
|
|
14
|
+
"@fragno-dev/cli": fragnoCliVersion,
|
|
15
|
+
"@types/node": "^22",
|
|
16
|
+
},
|
|
17
|
+
peerDependencies: {
|
|
18
|
+
typescript: "^5",
|
|
19
|
+
react: ">=18.0.0",
|
|
20
|
+
svelte: ">=4.0.0",
|
|
21
|
+
"solid-js": ">=1.0.0",
|
|
22
|
+
vue: ">=3.0.0",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const databasePkg: Record<string, unknown> = {
|
|
27
|
+
dependencies: {
|
|
28
|
+
"@fragno-dev/db": fragnoDbVersion,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
4
31
|
|
|
5
32
|
export const buildToolPkg: Record<BuildTools, Record<string, unknown>> = {
|
|
6
33
|
none: {},
|
package/src/utils.ts
CHANGED
|
@@ -5,7 +5,9 @@ export function mkdirp(dir: string): void {
|
|
|
5
5
|
try {
|
|
6
6
|
fs.mkdirSync(dir, { recursive: true });
|
|
7
7
|
} catch (e: unknown) {
|
|
8
|
-
if (e instanceof Error && "code" in e && e.code === "EEXIST")
|
|
8
|
+
if (e instanceof Error && "code" in e && e.code === "EEXIST") {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
9
11
|
throw e;
|
|
10
12
|
}
|
|
11
13
|
}
|
|
@@ -54,7 +56,9 @@ export function copy(
|
|
|
54
56
|
to: string,
|
|
55
57
|
rename: (basename: string) => string = identity,
|
|
56
58
|
): void {
|
|
57
|
-
if (!fs.existsSync(from))
|
|
59
|
+
if (!fs.existsSync(from)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
58
62
|
|
|
59
63
|
const stats = fs.statSync(from);
|
|
60
64
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"description": "A Fragno fragment",
|
|
3
3
|
"version": "0.0.1",
|
|
4
4
|
"files": ["dist"],
|
|
5
|
-
"keywords": ["fragno", "typescript", "react", "vue", "svelte"],
|
|
5
|
+
"keywords": ["fragno", "typescript", "react", "vue", "svelte", "solidjs"],
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"types": "./dist/node/index.d.ts",
|
|
@@ -32,6 +32,14 @@
|
|
|
32
32
|
"types": "./dist/browser/client/svelte.d.ts",
|
|
33
33
|
"default": "./dist/browser/client/svelte.js"
|
|
34
34
|
},
|
|
35
|
+
"./solid": {
|
|
36
|
+
"development": {
|
|
37
|
+
"browser": "./dist/browser/client/solid.js",
|
|
38
|
+
"default": "./src/client/solid.ts"
|
|
39
|
+
},
|
|
40
|
+
"types": "./dist/browser/client/solid.d.ts",
|
|
41
|
+
"default": "./dist/browser/client/solid.js"
|
|
42
|
+
},
|
|
35
43
|
"./vanilla": {
|
|
36
44
|
"development": {
|
|
37
45
|
"browser": "./dist/browser/client/vanilla.js",
|
|
@@ -48,18 +56,5 @@
|
|
|
48
56
|
"types:check": "tsc --noEmit"
|
|
49
57
|
},
|
|
50
58
|
"type": "module",
|
|
51
|
-
"
|
|
52
|
-
"@fragno-dev/core": "^0.0.6",
|
|
53
|
-
"zod": "^4.0.5"
|
|
54
|
-
},
|
|
55
|
-
"devDependencies": {
|
|
56
|
-
"@types/node": "^20"
|
|
57
|
-
},
|
|
58
|
-
"private": true,
|
|
59
|
-
"peerDependencies": {
|
|
60
|
-
"typescript": "^5",
|
|
61
|
-
"react": ">=18.0.0",
|
|
62
|
-
"svelte": ">=4.0.0",
|
|
63
|
-
"vue": ">=3.0.0"
|
|
64
|
-
}
|
|
59
|
+
"private": true
|
|
65
60
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useFragno } from "@fragno-dev/core/solid";
|
|
2
|
+
import { createExampleFragmentClients } from "..";
|
|
3
|
+
import type { FragnoPublicClientConfig } from "@fragno-dev/core";
|
|
4
|
+
|
|
5
|
+
export function createExampleFragmentClient(config: FragnoPublicClientConfig = {}) {
|
|
6
|
+
return useFragno(createExampleFragmentClients(config));
|
|
7
|
+
}
|
|
@@ -56,12 +56,12 @@ const exampleRoutesFactory = defineRoutes<ExampleConfig, ExampleDeps, ExampleSer
|
|
|
56
56
|
);
|
|
57
57
|
|
|
58
58
|
const exampleFragmentDefinition = defineFragment<ExampleConfig>("example-fragment")
|
|
59
|
-
.withDependencies((config
|
|
59
|
+
.withDependencies(({ config }) => {
|
|
60
60
|
return {
|
|
61
61
|
serverSideData: { value: config.initialData ?? "Hello World! This is a server-side data." },
|
|
62
62
|
};
|
|
63
63
|
})
|
|
64
|
-
.withServices((
|
|
64
|
+
.withServices(({ deps }) => {
|
|
65
65
|
return {
|
|
66
66
|
getData: () => deps.serverSideData.value,
|
|
67
67
|
};
|
|
@@ -24,6 +24,95 @@ Fragments follow a core pattern:
|
|
|
24
24
|
2. **Client-side**: Auto-generated type-safe hooks for each route
|
|
25
25
|
3. **Code splitting**: Server-only code (handlers, dependencies) is stripped from client bundles
|
|
26
26
|
|
|
27
|
+
## Database Integration (Optional)
|
|
28
|
+
|
|
29
|
+
Some Fragments require persistent storage. Fragno provides an optional database layer via
|
|
30
|
+
`@fragno-dev/db` that integrates with your users' existing databases.
|
|
31
|
+
|
|
32
|
+
### When to Use Database Integration
|
|
33
|
+
|
|
34
|
+
Use `defineFragmentWithDatabase()` when your Fragment needs to:
|
|
35
|
+
|
|
36
|
+
- Store persistent data (comments, likes, user preferences, etc.)
|
|
37
|
+
- Query structured data efficiently
|
|
38
|
+
- Maintain data integrity with indexes and constraints
|
|
39
|
+
- Provide users with full control over their data
|
|
40
|
+
|
|
41
|
+
### Schema Definition
|
|
42
|
+
|
|
43
|
+
Database schemas are defined in a separate `schema.ts` file using the Fragno schema builder:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { column, idColumn, schema } from "@fragno-dev/db/schema";
|
|
47
|
+
|
|
48
|
+
export const noteSchema = schema((s) => {
|
|
49
|
+
return s.addTable("note", (t) => {
|
|
50
|
+
return t
|
|
51
|
+
.addColumn("id", idColumn()) // Auto-generated ID
|
|
52
|
+
.addColumn("content", column("string"))
|
|
53
|
+
.addColumn("userId", column("string"))
|
|
54
|
+
.addColumn("createdAt", column("timestamp").defaultTo$("now"))
|
|
55
|
+
.createIndex("idx_note_user", ["userId"]); // Index for efficient queries
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Key concepts**:
|
|
61
|
+
|
|
62
|
+
- **Append-only**: Schemas use an append-only log approach. Never modify existing operations -
|
|
63
|
+
always add new ones
|
|
64
|
+
- **Versioning**: Each schema operation increments the version number
|
|
65
|
+
- **Indexes**: Create indexes on columns you'll frequently query (e.g., foreign keys, user IDs)
|
|
66
|
+
- **Defaults**: Use `.defaultTo(value)` or `.defaultTo$("now")` for timestamps
|
|
67
|
+
|
|
68
|
+
### Using the ORM
|
|
69
|
+
|
|
70
|
+
The ORM is available in both `withDependencies()` and `withServices()` via the `orm` parameter:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const fragmentDef = defineFragmentWithDatabase<Config>("my-fragment")
|
|
74
|
+
.withDatabase(mySchema)
|
|
75
|
+
.withServices(({ orm }) => {
|
|
76
|
+
return {
|
|
77
|
+
createNote: async (note) => {
|
|
78
|
+
const id = await orm.create("note", note);
|
|
79
|
+
return { id: id.toJSON(), ...note };
|
|
80
|
+
},
|
|
81
|
+
getNotesByUser: (userId: string) => {
|
|
82
|
+
// Use whereIndex for efficient indexed queries
|
|
83
|
+
return orm.find("note", (b) =>
|
|
84
|
+
b.whereIndex("idx_note_user", (eb) => eb("userId", "=", userId)),
|
|
85
|
+
);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**ORM methods**:
|
|
92
|
+
|
|
93
|
+
- `orm.create(table, data)` - Insert a row, returns FragnoId
|
|
94
|
+
- `orm.find(table, builder)` - Query rows with filtering
|
|
95
|
+
- `orm.findOne(table, builder)` - Query a single row
|
|
96
|
+
- `orm.update(table, id, data)` - Update a row by ID
|
|
97
|
+
- `orm.delete(table, id)` - Delete a row by ID
|
|
98
|
+
- `.whereIndex(indexName, condition)` - Use indexes for efficient queries
|
|
99
|
+
|
|
100
|
+
### Fragment Configuration
|
|
101
|
+
|
|
102
|
+
Database-enabled Fragments require `FragnoPublicConfigWithDatabase`:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
export function createMyFragment(
|
|
106
|
+
config: MyFragmentConfig = {},
|
|
107
|
+
options: FragnoPublicConfigWithDatabase, // Enforces databaseAdapter requirement
|
|
108
|
+
) {
|
|
109
|
+
return createFragment(fragmentDef, config, [], options);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For complete database documentation, see:
|
|
114
|
+
https://fragno.dev/docs/for-library-authors/database-integration/overview.md
|
|
115
|
+
|
|
27
116
|
## File Structure & Core Concepts
|
|
28
117
|
|
|
29
118
|
### `src/index.ts` - Main Fragment Definition
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineRoute,
|
|
3
|
+
defineRoutes,
|
|
4
|
+
createFragment,
|
|
5
|
+
type FragnoPublicClientConfig,
|
|
6
|
+
} from "@fragno-dev/core";
|
|
7
|
+
import { createClientBuilder } from "@fragno-dev/core/client";
|
|
8
|
+
import {
|
|
9
|
+
defineFragmentWithDatabase,
|
|
10
|
+
type FragnoPublicConfigWithDatabase,
|
|
11
|
+
} from "@fragno-dev/db/fragment";
|
|
12
|
+
import type { AbstractQuery, TableToInsertValues } from "@fragno-dev/db/query";
|
|
13
|
+
import { noteSchema } from "./schema";
|
|
14
|
+
|
|
15
|
+
// NOTE: We use zod here for defining schemas, but any StandardSchema library can be used!
|
|
16
|
+
// For a complete list see:
|
|
17
|
+
// https://github.com/standard-schema/standard-schema#what-schema-libraries-implement-the-spec
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
export interface ExampleConfig {
|
|
21
|
+
// Add any server-side configuration here if needed
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type ExampleServices = {
|
|
25
|
+
createNote: (note: TableToInsertValues<typeof noteSchema.tables.note>) => Promise<{
|
|
26
|
+
id: string;
|
|
27
|
+
content: string;
|
|
28
|
+
userId: string;
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
}>;
|
|
31
|
+
getNotes: () => Promise<
|
|
32
|
+
Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
content: string;
|
|
35
|
+
userId: string;
|
|
36
|
+
createdAt: Date;
|
|
37
|
+
}>
|
|
38
|
+
>;
|
|
39
|
+
getNotesByUser: (userId: string) => Promise<
|
|
40
|
+
Array<{
|
|
41
|
+
id: string;
|
|
42
|
+
content: string;
|
|
43
|
+
userId: string;
|
|
44
|
+
createdAt: Date;
|
|
45
|
+
}>
|
|
46
|
+
>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type ExampleDeps = {
|
|
50
|
+
orm: AbstractQuery<typeof noteSchema>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const exampleRoutesFactory = defineRoutes<ExampleConfig, ExampleDeps, ExampleServices>().create(
|
|
54
|
+
({ services }) => {
|
|
55
|
+
return [
|
|
56
|
+
defineRoute({
|
|
57
|
+
method: "GET",
|
|
58
|
+
path: "/notes",
|
|
59
|
+
queryParameters: ["userId"],
|
|
60
|
+
outputSchema: z.array(
|
|
61
|
+
z.object({
|
|
62
|
+
id: z.string(),
|
|
63
|
+
content: z.string(),
|
|
64
|
+
userId: z.string(),
|
|
65
|
+
createdAt: z.date(),
|
|
66
|
+
}),
|
|
67
|
+
),
|
|
68
|
+
handler: async ({ query }, { json }) => {
|
|
69
|
+
const userId = query.get("userId");
|
|
70
|
+
|
|
71
|
+
if (userId) {
|
|
72
|
+
const notes = await services.getNotesByUser(userId);
|
|
73
|
+
return json(notes);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const notes = await services.getNotes();
|
|
77
|
+
return json(notes);
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
|
|
81
|
+
defineRoute({
|
|
82
|
+
method: "POST",
|
|
83
|
+
path: "/notes",
|
|
84
|
+
inputSchema: z.object({ content: z.string(), userId: z.string() }),
|
|
85
|
+
outputSchema: z.object({
|
|
86
|
+
id: z.string(),
|
|
87
|
+
content: z.string(),
|
|
88
|
+
userId: z.string(),
|
|
89
|
+
createdAt: z.date(),
|
|
90
|
+
}),
|
|
91
|
+
errorCodes: [],
|
|
92
|
+
handler: async ({ input }, { json }) => {
|
|
93
|
+
const { content, userId } = await input.valid();
|
|
94
|
+
|
|
95
|
+
const note = await services.createNote({ content, userId });
|
|
96
|
+
return json(note);
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
99
|
+
];
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const exampleFragmentDefinition = defineFragmentWithDatabase<ExampleConfig>("example-fragment")
|
|
104
|
+
.withDatabase(noteSchema)
|
|
105
|
+
.withServices(({ orm }) => {
|
|
106
|
+
return {
|
|
107
|
+
createNote: async (note: TableToInsertValues<typeof noteSchema.tables.note>) => {
|
|
108
|
+
const id = await orm.create("note", note);
|
|
109
|
+
return {
|
|
110
|
+
...note,
|
|
111
|
+
id: id.toJSON(),
|
|
112
|
+
createdAt: note.createdAt ?? new Date(),
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
getNotes: () => {
|
|
116
|
+
return orm.find("note", (b) => b);
|
|
117
|
+
},
|
|
118
|
+
getNotesByUser: (userId: string) => {
|
|
119
|
+
return orm.find("note", (b) =>
|
|
120
|
+
b.whereIndex("idx_note_user", (eb) => eb("userId", "=", userId)),
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export function createExampleFragment(
|
|
127
|
+
config: ExampleConfig = {},
|
|
128
|
+
fragnoConfig: FragnoPublicConfigWithDatabase,
|
|
129
|
+
) {
|
|
130
|
+
return createFragment(exampleFragmentDefinition, config, [exampleRoutesFactory], fragnoConfig);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function createExampleFragmentClients(fragnoConfig: FragnoPublicClientConfig) {
|
|
134
|
+
const b = createClientBuilder(exampleFragmentDefinition, fragnoConfig, [exampleRoutesFactory]);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
useNotes: b.createHook("/notes"),
|
|
138
|
+
useCreateNote: b.createMutator("POST", "/notes"),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export type { FragnoRouteConfig } from "@fragno-dev/core/api";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { column, idColumn, schema } from "@fragno-dev/db/schema";
|
|
2
|
+
|
|
3
|
+
export const noteSchema = schema((s) => {
|
|
4
|
+
return s.addTable("note", (t) => {
|
|
5
|
+
return t
|
|
6
|
+
.addColumn("id", idColumn())
|
|
7
|
+
.addColumn("content", column("string"))
|
|
8
|
+
.addColumn("userId", column("string"))
|
|
9
|
+
.addColumn("createdAt", column("timestamp").defaultTo$("now"))
|
|
10
|
+
.createIndex("idx_note_user", ["userId"]);
|
|
11
|
+
});
|
|
12
|
+
});
|
package/.turbo/turbo-test.log
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
$ vitest run
|
|
2
|
-
|
|
3
|
-
[1m[46m RUN [49m[22m [36mv3.2.4 [39m[90m/home/runner/work/fragno/fragno/packages/create[39m
|
|
4
|
-
[2mCoverage enabled with [22m[33mistanbul[39m
|
|
5
|
-
|
|
6
|
-
[32m✓[39m src/utils.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
7
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with rspack
|
|
8
|
-
[22m[39mtemp /tmp/fragment-test-tsdown-1760971350638
|
|
9
|
-
|
|
10
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with tsdown[2m > [22m[2mpackage.json correctly templated
|
|
11
|
-
[22m[39mtemp /tmp/fragment-test-esbuild-1760971350646
|
|
12
|
-
|
|
13
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with esbuild[2m > [22m[2mpackage.json correctly templated
|
|
14
|
-
[22m[39mtemp /tmp/fragment-test-vite-1760971350646
|
|
15
|
-
|
|
16
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with vite[2m > [22m[2mpackage.json correctly templated
|
|
17
|
-
[22m[39mtemp /tmp/fragment-test-rollup-1760971350655
|
|
18
|
-
|
|
19
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with rollup[2m > [22m[2mpackage.json correctly templated
|
|
20
|
-
[22m[39mtemp /tmp/fragment-test-webpack-1760971350655
|
|
21
|
-
|
|
22
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with webpack[2m > [22m[2mpackage.json correctly templated
|
|
23
|
-
[22m[39mtemp /tmp/fragment-test-rspack-1760971350655
|
|
24
|
-
|
|
25
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with webpack[2m > [22m[2mcompiles
|
|
26
|
-
[22m[39m
|
|
27
|
-
|
|
28
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with rspack[2m > [22m[2mcompiles
|
|
29
|
-
[22m[39m
|
|
30
|
-
|
|
31
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with rollup
|
|
32
|
-
[22m[39m
|
|
33
|
-
|
|
34
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with esbuild[2m > [22m[2mbuilds
|
|
35
|
-
[22m[39m
|
|
36
|
-
|
|
37
|
-
[90mstdout[2m | src/integration.test.ts
|
|
38
|
-
[22m[39m
|
|
39
|
-
|
|
40
|
-
[90mstdout[2m | src/integration.test.ts[2m > [22m[2mfragment with webpack[2m > [22m[2mbuilds
|
|
41
|
-
[22m[39m
|
|
42
|
-
|
|
43
|
-
[32m✓[39m src/integration.test.ts [2m([22m[2m30 tests[22m[2m | [22m[33m1 skipped[39m[2m)[22m[33m 44063[2mms[22m[39m
|
|
44
|
-
[33m[2m✓[22m[39m fragment with tsdown[2m > [22minstalls [33m 4713[2mms[22m[39m
|
|
45
|
-
[33m[2m✓[22m[39m fragment with tsdown[2m > [22mcompiles [33m 10564[2mms[22m[39m
|
|
46
|
-
[33m[2m✓[22m[39m fragment with tsdown[2m > [22mbuilds [33m 22349[2mms[22m[39m
|
|
47
|
-
[33m[2m✓[22m[39m fragment with esbuild[2m > [22minstalls [33m 4662[2mms[22m[39m
|
|
48
|
-
[33m[2m✓[22m[39m fragment with esbuild[2m > [22mcompiles [33m 10549[2mms[22m[39m
|
|
49
|
-
[33m[2m✓[22m[39m fragment with esbuild[2m > [22mbuilds [33m 4265[2mms[22m[39m
|
|
50
|
-
[33m[2m✓[22m[39m fragment with vite[2m > [22minstalls [33m 4586[2mms[22m[39m
|
|
51
|
-
[33m[2m✓[22m[39m fragment with vite[2m > [22mcompiles [33m 10195[2mms[22m[39m
|
|
52
|
-
[33m[2m✓[22m[39m fragment with vite[2m > [22mbuilds [33m 15462[2mms[22m[39m
|
|
53
|
-
[33m[2m✓[22m[39m fragment with rollup[2m > [22minstalls [33m 4570[2mms[22m[39m
|
|
54
|
-
[33m[2m✓[22m[39m fragment with rollup[2m > [22mcompiles [33m 9853[2mms[22m[39m
|
|
55
|
-
[33m[2m✓[22m[39m fragment with webpack[2m > [22minstalls [33m 4686[2mms[22m[39m
|
|
56
|
-
[33m[2m✓[22m[39m fragment with webpack[2m > [22mcompiles [33m 10725[2mms[22m[39m
|
|
57
|
-
[33m[2m✓[22m[39m fragment with webpack[2m > [22mbuilds [33m 23445[2mms[22m[39m
|
|
58
|
-
[33m[2m✓[22m[39m fragment with rspack[2m > [22minstalls [33m 5032[2mms[22m[39m
|
|
59
|
-
[33m[2m✓[22m[39m fragment with rspack[2m > [22mcompiles [33m 11494[2mms[22m[39m
|
|
60
|
-
[33m[2m✓[22m[39m fragment with rspack[2m > [22mbuilds [33m 9897[2mms[22m[39m
|
|
61
|
-
|
|
62
|
-
[2m Test Files [22m [1m[32m2 passed[39m[22m[90m (2)[39m
|
|
63
|
-
[2m Tests [22m [1m[32m30 passed[39m[22m[2m | [22m[33m1 skipped[39m[90m (31)[39m
|
|
64
|
-
[2m Start at [22m 14:42:27
|
|
65
|
-
[2m Duration [22m 46.59s[2m (transform 1.38s, setup 0ms, collect 2.20s, tests 44.09s, environment 1ms, prepare 804ms)[22m
|
|
66
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
$ tsc --noEmit
|