@freema/drobek-modules 0.3.3
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/LICENSE +661 -0
- package/README.md +53 -0
- package/dist/chunk-WHKPW5MP.js +6611 -0
- package/dist/index.d.ts +1604 -0
- package/dist/index.js +373 -0
- package/dist/mail-guard.d-BKJhsVA2.d.ts +2097 -0
- package/dist/migrations/core/0000_dusty_scarecrow.sql +84 -0
- package/dist/migrations/core/0001_busy_orphan.sql +69 -0
- package/dist/migrations/core/0002_odd_alex_power.sql +17 -0
- package/dist/migrations/core/0003_nosy_shatterstar.sql +26 -0
- package/dist/migrations/core/0004_nice_ben_parker.sql +27 -0
- package/dist/migrations/core/0005_panoramic_bill_hollister.sql +4 -0
- package/dist/migrations/core/0006_outgoing_ricochet.sql +29 -0
- package/dist/migrations/core/0007_app_versions.sql +95 -0
- package/dist/migrations/core/0008_user_bound_tokens.sql +42 -0
- package/dist/migrations/core/0009_app_name.sql +1 -0
- package/dist/migrations/core/0010_apps_origin.sql +12 -0
- package/dist/migrations/core/0011_modules.sql +32 -0
- package/dist/migrations/core/0012_data_module_tables.sql +9 -0
- package/dist/migrations/core/0014_get_logs.sql +26 -0
- package/dist/migrations/core/0016_apps_slug_release.sql +8 -0
- package/dist/migrations/core/0018_custom_domains.sql +22 -0
- package/dist/migrations/core/0021_abuse_reports.sql +23 -0
- package/dist/migrations/core/0022_gallery.sql +20 -0
- package/dist/migrations/core/0023_workspace_modules.sql +13 -0
- package/dist/migrations/core/0024_app_assets.sql +18 -0
- package/dist/migrations/core/0025_app_asset_snapshots.sql +28 -0
- package/dist/migrations/core/0026_publish_approval.sql +13 -0
- package/dist/migrations/core/0027_publish_block.sql +6 -0
- package/dist/migrations/core/meta/_journal.json +167 -0
- package/dist/testing.d.ts +269 -0
- package/dist/testing.js +1569 -0
- package/package.json +63 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-- NSO-362: assets honour publish. `app_assets` becomes the draft (what the
|
|
2
|
+
-- preview host serves); `app_version_assets` holds the set a publish froze for
|
|
3
|
+
-- a version (what the production host serves), `app_versions.assets_frozen_at`
|
|
4
|
+
-- marks a version that has one. Upgrade: the assets of every published app are
|
|
5
|
+
-- frozen as its live version's set, so nothing a public URL serves today
|
|
6
|
+
-- disappears; they stay the draft too.
|
|
7
|
+
CREATE TABLE "app_version_assets" (
|
|
8
|
+
"version_id" text NOT NULL,
|
|
9
|
+
"app_id" text NOT NULL,
|
|
10
|
+
"name" text NOT NULL,
|
|
11
|
+
"content_type" text NOT NULL,
|
|
12
|
+
"size" bigint NOT NULL,
|
|
13
|
+
"sha256" text NOT NULL,
|
|
14
|
+
"storage_key" text NOT NULL,
|
|
15
|
+
"updated_at" timestamp DEFAULT now() NOT NULL,
|
|
16
|
+
CONSTRAINT "app_version_assets_version_id_name_pk" PRIMARY KEY("version_id","name")
|
|
17
|
+
);
|
|
18
|
+
--> statement-breakpoint
|
|
19
|
+
ALTER TABLE "app_versions" ADD COLUMN "assets_frozen_at" timestamp;--> statement-breakpoint
|
|
20
|
+
ALTER TABLE "app_version_assets" ADD CONSTRAINT "app_version_assets_version_id_app_versions_id_fk" FOREIGN KEY ("version_id") REFERENCES "public"."app_versions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
21
|
+
ALTER TABLE "app_version_assets" ADD CONSTRAINT "app_version_assets_app_id_apps_id_fk" FOREIGN KEY ("app_id") REFERENCES "public"."apps"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
22
|
+
CREATE INDEX "app_version_assets_app_idx" ON "app_version_assets" USING btree ("app_id");--> statement-breakpoint
|
|
23
|
+
INSERT INTO "app_version_assets" ("version_id", "app_id", "name", "content_type", "size", "sha256", "storage_key", "updated_at")
|
|
24
|
+
SELECT a."published_version_id", aa."app_id", aa."name", aa."content_type", aa."size", aa."sha256", aa."storage_key", aa."updated_at"
|
|
25
|
+
FROM "app_assets" aa JOIN "apps" a ON a."id" = aa."app_id"
|
|
26
|
+
WHERE a."published_version_id" IS NOT NULL;--> statement-breakpoint
|
|
27
|
+
UPDATE "app_versions" SET "assets_frozen_at" = now()
|
|
28
|
+
WHERE "id" IN (SELECT "published_version_id" FROM "apps" WHERE "published_version_id" IS NOT NULL);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- NSO-366: PUBLISH_APPROVAL=approval — a super-admin decides per workspace
|
|
2
|
+
-- whether it may publish. `publish_approved_at` null = not approved; the
|
|
3
|
+
-- approval request columns dedupe the operator e-mail. Upgrade: every
|
|
4
|
+
-- workspace that already has a published app is approved now, so turning
|
|
5
|
+
-- approval on never takes the next publish of a live app away.
|
|
6
|
+
ALTER TABLE "workspaces" ADD COLUMN "publish_approved_at" timestamp with time zone;--> statement-breakpoint
|
|
7
|
+
ALTER TABLE "workspaces" ADD COLUMN "publish_approved_by" text;--> statement-breakpoint
|
|
8
|
+
ALTER TABLE "workspaces" ADD COLUMN "publish_approval_requested_at" timestamp with time zone;--> statement-breakpoint
|
|
9
|
+
ALTER TABLE "workspaces" ADD COLUMN "publish_approval_requested_by" text;--> statement-breakpoint
|
|
10
|
+
ALTER TABLE "workspaces" ADD CONSTRAINT "workspaces_publish_approved_by_users_id_fk" FOREIGN KEY ("publish_approved_by") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
|
11
|
+
ALTER TABLE "workspaces" ADD CONSTRAINT "workspaces_publish_approval_requested_by_users_id_fk" FOREIGN KEY ("publish_approval_requested_by") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
|
12
|
+
UPDATE "workspaces" SET "publish_approved_at" = now()
|
|
13
|
+
WHERE "id" IN (SELECT "workspace_id" FROM "apps" WHERE "published_version_id" IS NOT NULL AND "deleted_at" IS NULL);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- NSO-366: a super-admin can turn publishing off for a workspace, in every
|
|
2
|
+
-- PUBLISH_APPROVAL mode. Blocked = publish_blocked_at set; allowed =
|
|
3
|
+
-- publish_approved_at set (0026); neither = the server mode decides.
|
|
4
|
+
ALTER TABLE "workspaces" ADD COLUMN "publish_blocked_at" timestamp with time zone;--> statement-breakpoint
|
|
5
|
+
ALTER TABLE "workspaces" ADD COLUMN "publish_blocked_by" text;--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "workspaces" ADD CONSTRAINT "workspaces_publish_blocked_by_users_id_fk" FOREIGN KEY ("publish_blocked_by") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "7",
|
|
3
|
+
"dialect": "postgresql",
|
|
4
|
+
"entries": [
|
|
5
|
+
{
|
|
6
|
+
"idx": 0,
|
|
7
|
+
"version": "7",
|
|
8
|
+
"when": 1782985986575,
|
|
9
|
+
"tag": "0000_dusty_scarecrow",
|
|
10
|
+
"breakpoints": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"idx": 1,
|
|
14
|
+
"version": "7",
|
|
15
|
+
"when": 1783043106616,
|
|
16
|
+
"tag": "0001_busy_orphan",
|
|
17
|
+
"breakpoints": true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"idx": 2,
|
|
21
|
+
"version": "7",
|
|
22
|
+
"when": 1783067845061,
|
|
23
|
+
"tag": "0002_odd_alex_power",
|
|
24
|
+
"breakpoints": true
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"idx": 3,
|
|
28
|
+
"version": "7",
|
|
29
|
+
"when": 1783096383394,
|
|
30
|
+
"tag": "0003_nosy_shatterstar",
|
|
31
|
+
"breakpoints": true
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"idx": 4,
|
|
35
|
+
"version": "7",
|
|
36
|
+
"when": 1783125113132,
|
|
37
|
+
"tag": "0004_nice_ben_parker",
|
|
38
|
+
"breakpoints": true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"idx": 5,
|
|
42
|
+
"version": "7",
|
|
43
|
+
"when": 1783143918577,
|
|
44
|
+
"tag": "0005_panoramic_bill_hollister",
|
|
45
|
+
"breakpoints": true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"idx": 6,
|
|
49
|
+
"version": "7",
|
|
50
|
+
"when": 1783151896848,
|
|
51
|
+
"tag": "0006_outgoing_ricochet",
|
|
52
|
+
"breakpoints": true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"idx": 7,
|
|
56
|
+
"version": "7",
|
|
57
|
+
"when": 1790132000000,
|
|
58
|
+
"tag": "0007_app_versions",
|
|
59
|
+
"breakpoints": true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"idx": 8,
|
|
63
|
+
"version": "7",
|
|
64
|
+
"when": 1790146977226,
|
|
65
|
+
"tag": "0008_user_bound_tokens",
|
|
66
|
+
"breakpoints": true
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"idx": 9,
|
|
70
|
+
"version": "7",
|
|
71
|
+
"when": 1790149105340,
|
|
72
|
+
"tag": "0009_app_name",
|
|
73
|
+
"breakpoints": true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"idx": 10,
|
|
77
|
+
"version": "7",
|
|
78
|
+
"when": 1790152014046,
|
|
79
|
+
"tag": "0010_apps_origin",
|
|
80
|
+
"breakpoints": true
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"idx": 11,
|
|
84
|
+
"version": "7",
|
|
85
|
+
"when": 1790162052842,
|
|
86
|
+
"tag": "0011_modules",
|
|
87
|
+
"breakpoints": true
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"idx": 12,
|
|
91
|
+
"version": "7",
|
|
92
|
+
"when": 1790175801064,
|
|
93
|
+
"tag": "0012_data_module_tables",
|
|
94
|
+
"breakpoints": true
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"idx": 14,
|
|
98
|
+
"version": "7",
|
|
99
|
+
"when": 1790192202963,
|
|
100
|
+
"tag": "0014_get_logs",
|
|
101
|
+
"breakpoints": true
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"idx": 16,
|
|
105
|
+
"version": "7",
|
|
106
|
+
"when": 1790194823940,
|
|
107
|
+
"tag": "0016_apps_slug_release",
|
|
108
|
+
"breakpoints": true
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"idx": 18,
|
|
112
|
+
"version": "7",
|
|
113
|
+
"when": 1790194890971,
|
|
114
|
+
"tag": "0018_custom_domains",
|
|
115
|
+
"breakpoints": true
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"idx": 21,
|
|
119
|
+
"version": "7",
|
|
120
|
+
"when": 1790196335795,
|
|
121
|
+
"tag": "0021_abuse_reports",
|
|
122
|
+
"breakpoints": true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"idx": 22,
|
|
126
|
+
"version": "7",
|
|
127
|
+
"when": 1790432415711,
|
|
128
|
+
"tag": "0022_gallery",
|
|
129
|
+
"breakpoints": true
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"idx": 23,
|
|
133
|
+
"version": "7",
|
|
134
|
+
"when": 1790432800000,
|
|
135
|
+
"tag": "0023_workspace_modules",
|
|
136
|
+
"breakpoints": true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"idx": 24,
|
|
140
|
+
"version": "7",
|
|
141
|
+
"when": 1790433136356,
|
|
142
|
+
"tag": "0024_app_assets",
|
|
143
|
+
"breakpoints": true
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"idx": 25,
|
|
147
|
+
"version": "7",
|
|
148
|
+
"when": 1790437501780,
|
|
149
|
+
"tag": "0025_app_asset_snapshots",
|
|
150
|
+
"breakpoints": true
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"idx": 26,
|
|
154
|
+
"version": "7",
|
|
155
|
+
"when": 1790493019726,
|
|
156
|
+
"tag": "0026_publish_approval",
|
|
157
|
+
"breakpoints": true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"idx": 27,
|
|
161
|
+
"version": "7",
|
|
162
|
+
"when": 1790496410618,
|
|
163
|
+
"tag": "0027_publish_block",
|
|
164
|
+
"breakpoints": true
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { AnyModule, SdkBundle, ModuleContext, MailEnvelope, Principal, EndUserCallbackResult, HookApp, DB, Logger, MailGuard } from './index.js';
|
|
2
|
+
import 'node:stream';
|
|
3
|
+
import 'drizzle-orm/postgres-js';
|
|
4
|
+
import 'zod';
|
|
5
|
+
|
|
6
|
+
/** One skill as the checker sees it (a module's `skill.markdown`, or a general `skills/<name>/SKILL.md`). */
|
|
7
|
+
interface SkillSource {
|
|
8
|
+
name: string;
|
|
9
|
+
kind: 'module' | 'general';
|
|
10
|
+
useWhen: string;
|
|
11
|
+
/** The markdown skill_info returns (a general skill: without its frontmatter). */
|
|
12
|
+
content: string;
|
|
13
|
+
/** The SKILL.md as named in the issues (e.g. `SKILL.md`, `modules/auth/SKILL.md`). */
|
|
14
|
+
file: string;
|
|
15
|
+
/** The file's full text (frontmatter included). */
|
|
16
|
+
fileText: string;
|
|
17
|
+
module?: AnyModule;
|
|
18
|
+
}
|
|
19
|
+
/** One finding of `checkSkill` / `checkSkillSources`. */
|
|
20
|
+
interface SkillIssue {
|
|
21
|
+
skill: string;
|
|
22
|
+
/** The SKILL.md (see SkillSource.file). */
|
|
23
|
+
file: string;
|
|
24
|
+
/** 0-based index of the code block in the file; -1 when the issue is not about one block. */
|
|
25
|
+
block: number;
|
|
26
|
+
/** 1-based line in the SKILL.md (0 when the issue concerns the whole file). */
|
|
27
|
+
line: number;
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
/** `SKILL.md:12 (skill "erp", code block #2): message` */
|
|
31
|
+
declare function formatSkillIssue(p: SkillIssue): string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* `checkSkill(module)` (NSO-349) — the SKILL.md gate the built-in modules
|
|
35
|
+
* pass, for any module: a module author runs it in the module's own tests
|
|
36
|
+
* (`@drobek/modules/testing`), the repo gate (packages/skills-check) runs
|
|
37
|
+
* `checkSkillSources` over the built-in modules + the general skills.
|
|
38
|
+
*
|
|
39
|
+
* - the format: the five sections in order, ≤ 150 lines, a one-sentence
|
|
40
|
+
* "use when", working code first, only real error codes (the core
|
|
41
|
+
* catalogue + the module's own `errors`), present tense (format.ts);
|
|
42
|
+
* - the code: every fenced block compiled with drobek's compiler and
|
|
43
|
+
* typechecked against the sdk.d.ts of the module (+ `modules`), `ts api`
|
|
44
|
+
* blocks mutually assignable to the real SDK, configure_module payloads
|
|
45
|
+
* against the module's schema (examples.ts).
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
interface CheckSkillOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Other modules the skill's examples use next to this one (e.g. the
|
|
51
|
+
* built-in `auth` module for `drobek.auth`): their SDK is composed in and
|
|
52
|
+
* their configure_module payloads are checked. Default: none.
|
|
53
|
+
*/
|
|
54
|
+
modules?: AnyModule[];
|
|
55
|
+
/** The SKILL.md as named in the issues (default `SKILL.md`). */
|
|
56
|
+
file?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The directory whose node_modules resolve the examples' bare imports
|
|
59
|
+
* (`react` → @types/react, …); default: the working directory. An import
|
|
60
|
+
* that does not resolve is typed `any`.
|
|
61
|
+
*/
|
|
62
|
+
root?: string;
|
|
63
|
+
}
|
|
64
|
+
interface CheckSkillSourcesOptions {
|
|
65
|
+
/** The SDK bundle of `modules` (built when omitted). */
|
|
66
|
+
sdk?: SdkBundle;
|
|
67
|
+
/** See CheckSkillOptions.root. */
|
|
68
|
+
root?: string;
|
|
69
|
+
}
|
|
70
|
+
/** The error codes a skill may name: the core catalogue + its module's `errors` (a general skill: every module's). */
|
|
71
|
+
declare function knownErrorCodes(src: SkillSource, modules: AnyModule[]): Set<string>;
|
|
72
|
+
/** Format + code issues of `skills` on a server running `modules` (every module skill's module must be among them). */
|
|
73
|
+
declare function checkSkillSources(skills: SkillSource[], modules: AnyModule[], opts?: CheckSkillSourcesOptions): Promise<SkillIssue[]>;
|
|
74
|
+
/** The skill of one module as skill_info serves it. */
|
|
75
|
+
declare function moduleSkillSource(module: AnyModule, file?: string): SkillSource;
|
|
76
|
+
/**
|
|
77
|
+
* Check a module's skill (`defineModule({ skill })`) the way drobek checks
|
|
78
|
+
* its built-in modules. `[]` = it passes.
|
|
79
|
+
*
|
|
80
|
+
* const issues = await checkSkill(erp);
|
|
81
|
+
* expect(issues.map(formatSkillIssue)).toEqual([]);
|
|
82
|
+
*/
|
|
83
|
+
declare function checkSkill(module: AnyModule, opts?: CheckSkillOptions): Promise<SkillIssue[]>;
|
|
84
|
+
|
|
85
|
+
interface ExamplesOptions {
|
|
86
|
+
/** The SDK bundle of `modules` (built when omitted). */
|
|
87
|
+
sdk?: SdkBundle;
|
|
88
|
+
/** The directory whose node_modules resolve the examples' bare imports (default: the working directory). */
|
|
89
|
+
root?: string;
|
|
90
|
+
}
|
|
91
|
+
interface ExamplesReport {
|
|
92
|
+
problems: SkillIssue[];
|
|
93
|
+
counts: {
|
|
94
|
+
blocks: number;
|
|
95
|
+
compiled: number;
|
|
96
|
+
typechecked: number;
|
|
97
|
+
apiChecked: number;
|
|
98
|
+
configChecked: number;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Compile and typecheck every code block of `skills` against the SDK of
|
|
103
|
+
* `modules` (the server's sdk.d.ts + the inline declarations).
|
|
104
|
+
*/
|
|
105
|
+
declare function checkExamples(skills: SkillSource[], modules: AnyModule[], opts?: ExamplesOptions): Promise<ExamplesReport>;
|
|
106
|
+
|
|
107
|
+
declare const SKILL_SECTIONS: readonly ["1. When to use", "2. Minimal working code", "3. API and types", "4. Rules and limits", "5. Errors → fix"];
|
|
108
|
+
declare const SKILL_MAX_LINES = 150;
|
|
109
|
+
/**
|
|
110
|
+
* The format issues of one skill. `knownCodes`: the error codes the skill may
|
|
111
|
+
* name in "Errors → fix" (the core catalogue + the module's own `errors`).
|
|
112
|
+
*/
|
|
113
|
+
declare function skillFormatIssues(src: SkillSource, knownCodes: ReadonlySet<string>): SkillIssue[];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A tiny Markdown reader for the skills: fenced code blocks (with their info
|
|
117
|
+
* string) and `##` headings. Skills are plain CommonMark written by us, so a
|
|
118
|
+
* line scanner is enough — no dependency.
|
|
119
|
+
*/
|
|
120
|
+
interface CodeBlock {
|
|
121
|
+
/** First word of the info string (`tsx`, `json`, `html`, …); '' when none. */
|
|
122
|
+
lang: string;
|
|
123
|
+
/** The rest of the info string (`api`, `drobek.json`, …). */
|
|
124
|
+
meta: string;
|
|
125
|
+
code: string;
|
|
126
|
+
/** 1-based line of the opening fence. */
|
|
127
|
+
line: number;
|
|
128
|
+
/** 0-based index among the file's code blocks. */
|
|
129
|
+
index: number;
|
|
130
|
+
/** The `##` heading the block sits under ('' before the first). */
|
|
131
|
+
section: string;
|
|
132
|
+
}
|
|
133
|
+
interface Heading {
|
|
134
|
+
level: number;
|
|
135
|
+
text: string;
|
|
136
|
+
line: number;
|
|
137
|
+
}
|
|
138
|
+
declare function codeBlocks(markdown: string): CodeBlock[];
|
|
139
|
+
/** Every ATX heading outside code blocks. */
|
|
140
|
+
declare function headings(markdown: string): Heading[];
|
|
141
|
+
/** The text between the `##` heading that starts with `prefix` and the next `##` (fences included). */
|
|
142
|
+
declare function sectionText(markdown: string, prefix: string): string;
|
|
143
|
+
/** The markdown without its fenced code blocks (the prose an agent reads). */
|
|
144
|
+
declare function proseOf(markdown: string): string;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The folder of drobek's core migrations (journal `__drizzle_migrations_core`):
|
|
148
|
+
* apply it before a module's own migrations, whose tables reference
|
|
149
|
+
* `apps(id)`. The published package ships a copy (`dist/migrations/core`);
|
|
150
|
+
* in the drobek repository it is `packages/db/drizzle/migrations`.
|
|
151
|
+
*/
|
|
152
|
+
declare function coreMigrationsDir(): string;
|
|
153
|
+
/**
|
|
154
|
+
* A workspace + an app in a database with the core migrations applied — the
|
|
155
|
+
* `app` to pass to createModuleTestContext (module rows reference its id).
|
|
156
|
+
*/
|
|
157
|
+
declare function createTestApp(db: unknown, opts?: {
|
|
158
|
+
slug?: string;
|
|
159
|
+
}): Promise<HookApp>;
|
|
160
|
+
interface ModuleTestOptions {
|
|
161
|
+
/** A partial config (merged over configDefaults, then validated). */
|
|
162
|
+
config?: Record<string, unknown>;
|
|
163
|
+
principal?: Principal;
|
|
164
|
+
/** Secret name → plaintext. */
|
|
165
|
+
secrets?: Record<string, string>;
|
|
166
|
+
/** Limit overrides (the rest come from the module's defaults). */
|
|
167
|
+
limits?: Record<string, number>;
|
|
168
|
+
app?: Partial<HookApp>;
|
|
169
|
+
db?: DB;
|
|
170
|
+
log?: Logger;
|
|
171
|
+
/** The app host the requests come from (default `http://test--preview.apps.localhost`). */
|
|
172
|
+
origin?: string;
|
|
173
|
+
now?: () => number;
|
|
174
|
+
/** The app owners' addresses (`{ appOwners: true }` recipients; default none). */
|
|
175
|
+
owners?: string[];
|
|
176
|
+
/**
|
|
177
|
+
* The operator-wide e-mail guard core runs around every `ctx.email.send`
|
|
178
|
+
* (e.g. `memoryMailGuard(...)`): pass one to test how the module behaves
|
|
179
|
+
* while module e-mail is paused. Default: no guard.
|
|
180
|
+
*/
|
|
181
|
+
mailGuard?: MailGuard;
|
|
182
|
+
/**
|
|
183
|
+
* Slot → the contributions `ctx.contributions(slot)` returns (as the
|
|
184
|
+
* slot's schema would have parsed them; default: none — `[]`). A slot
|
|
185
|
+
* host's `compose` runs with them first, as at server start.
|
|
186
|
+
*/
|
|
187
|
+
contributions?: Record<string, unknown[]>;
|
|
188
|
+
}
|
|
189
|
+
/** One request to the module's `endUsers.callback` (the dashboard-host IdP callback). */
|
|
190
|
+
interface TestCallbackInit {
|
|
191
|
+
provider: string;
|
|
192
|
+
method?: 'GET' | 'POST';
|
|
193
|
+
query?: Record<string, string>;
|
|
194
|
+
body?: Record<string, string> | null;
|
|
195
|
+
/** Default `127.0.0.1`; `null` = no resolved client IP. */
|
|
196
|
+
clientIp?: string | null;
|
|
197
|
+
}
|
|
198
|
+
interface TestRequestInit {
|
|
199
|
+
/** A JSON body. */
|
|
200
|
+
body?: unknown;
|
|
201
|
+
/** A raw body instead (set its `content-type` in `headers`), e.g. multipart/form-data. */
|
|
202
|
+
rawBody?: Buffer | string;
|
|
203
|
+
/** A `bodyTypes: ['file']` route streams `rawBody` in chunks of this many bytes (default 64 KiB). */
|
|
204
|
+
chunkSize?: number;
|
|
205
|
+
query?: Record<string, string>;
|
|
206
|
+
headers?: Record<string, string>;
|
|
207
|
+
/** Default `127.0.0.1`; `null` = no resolved client IP (per-IP limits are skipped). */
|
|
208
|
+
clientIp?: string | null;
|
|
209
|
+
}
|
|
210
|
+
interface TestResponse {
|
|
211
|
+
status: number;
|
|
212
|
+
headers: Record<string, string>;
|
|
213
|
+
/** Parsed JSON (or the raw text when the body is not JSON). */
|
|
214
|
+
body: unknown;
|
|
215
|
+
/** The raw response bytes (a streamed body is collected). */
|
|
216
|
+
bytes: Buffer;
|
|
217
|
+
/** Request body bytes a streaming (`file`) route pulled before it stopped. */
|
|
218
|
+
bodyBytesRead: number;
|
|
219
|
+
}
|
|
220
|
+
interface ModuleTestContext {
|
|
221
|
+
ctx: ModuleContext<any>;
|
|
222
|
+
/**
|
|
223
|
+
* Run `method path` through the production pipeline. SDK header + same
|
|
224
|
+
* Origin are sent by default. Rejects — where production answers
|
|
225
|
+
* `500 internal_error` — when the handler throws something other than a
|
|
226
|
+
* ModuleError, or a ModuleError whose code is neither a core code nor in
|
|
227
|
+
* the module's `errors`.
|
|
228
|
+
*/
|
|
229
|
+
request(method: string, path: string, init?: TestRequestInit): Promise<TestResponse>;
|
|
230
|
+
/** Audit rows the module wrote (`<module>.<action>`). */
|
|
231
|
+
audits: {
|
|
232
|
+
action: string;
|
|
233
|
+
meta: Record<string, unknown>;
|
|
234
|
+
}[];
|
|
235
|
+
/**
|
|
236
|
+
* E-mails the module sent (resolved recipients, one entry per send). When
|
|
237
|
+
* the module under test is the mail authority (`mail`), its own `prepare`
|
|
238
|
+
* runs first (limits, envelope) exactly as core runs it.
|
|
239
|
+
*/
|
|
240
|
+
emails: ({
|
|
241
|
+
to: string[];
|
|
242
|
+
subject: string;
|
|
243
|
+
text: string;
|
|
244
|
+
kind: 'sign_in' | 'notification';
|
|
245
|
+
} & MailEnvelope)[];
|
|
246
|
+
/** Change who is calling. */
|
|
247
|
+
setPrincipal(principal: Principal): void;
|
|
248
|
+
/**
|
|
249
|
+
* Run the module's `confirmRequired(before, after, context)` the way
|
|
250
|
+
* configure_module does — both configs merged over configDefaults and
|
|
251
|
+
* validated, the context naming the test app and `db` ([] without a
|
|
252
|
+
* confirmRequired).
|
|
253
|
+
*/
|
|
254
|
+
confirm(before: Record<string, unknown>, after: Record<string, unknown>): Promise<string[]>;
|
|
255
|
+
/**
|
|
256
|
+
* Run the module's `endUsers.callback` the way core runs it for
|
|
257
|
+
* `/__drobek/auth/callback/:provider` on the dashboard host: the test app
|
|
258
|
+
* is the only live app (`services.app(id)` answers it for its id, null for
|
|
259
|
+
* any other), with the test config, secrets, limits and audits; the rate
|
|
260
|
+
* limiter shares the test clock. Rejects when the module has no callback.
|
|
261
|
+
*/
|
|
262
|
+
endUserCallback(init: TestCallbackInit): Promise<EndUserCallbackResult>;
|
|
263
|
+
/** The module as the test runs it (composed from `contributions` when it hosts slots). */
|
|
264
|
+
module: AnyModule;
|
|
265
|
+
}
|
|
266
|
+
declare function createModuleTestContext(declared: AnyModule, opts?: ModuleTestOptions): ModuleTestContext;
|
|
267
|
+
|
|
268
|
+
export { SKILL_MAX_LINES, SKILL_SECTIONS, checkExamples, checkSkill, checkSkillSources, codeBlocks, coreMigrationsDir, createModuleTestContext, createTestApp, formatSkillIssue, headings, knownErrorCodes, moduleSkillSource, proseOf, sectionText, skillFormatIssues };
|
|
269
|
+
export type { CheckSkillOptions, CheckSkillSourcesOptions, CodeBlock, ExamplesOptions, ExamplesReport, Heading, ModuleTestContext, ModuleTestOptions, SkillIssue, SkillSource, TestCallbackInit, TestRequestInit, TestResponse };
|