@cosmicdrift/kumiko-dev-server 0.368.0 → 0.370.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/dist/build.d.ts +1 -1
- package/dist/cli.d.ts +3 -3
- package/dist/compose-stacks.d.ts +57 -3
- package/dist/compose-stacks.js +88 -9
- package/dist/host-dispatch-adapter.d.ts +7 -0
- package/dist/host-dispatch-adapter.js +31 -0
- package/dist/index.d.ts +21 -20
- package/dist/index.js +2 -1
- package/dist/init-deploy-cli.js +6 -0
- package/dist/managed-files/app-scripts.d.ts +13 -0
- package/dist/managed-files/app-scripts.js +40 -0
- package/dist/managed-files/check.d.ts +34 -0
- package/dist/managed-files/check.js +109 -0
- package/dist/managed-files/index.d.ts +8 -0
- package/dist/managed-files/index.js +8 -0
- package/dist/managed-files/jsonc.d.ts +1 -0
- package/dist/managed-files/jsonc.js +12 -0
- package/dist/managed-files/line-diff.d.ts +2 -0
- package/dist/managed-files/line-diff.js +60 -0
- package/dist/managed-files/marker.d.ts +17 -0
- package/dist/managed-files/marker.js +49 -0
- package/dist/managed-files/port-registry.d.ts +17 -0
- package/dist/managed-files/port-registry.js +31 -0
- package/dist/managed-files/registry.d.ts +51 -0
- package/dist/managed-files/registry.js +115 -0
- package/dist/managed-files/static-app-config.d.ts +16 -0
- package/dist/managed-files/static-app-config.js +99 -0
- package/dist/managed-files/sync.d.ts +19 -0
- package/dist/managed-files/sync.js +101 -0
- package/dist/run-dev-app.d.ts +6 -1
- package/dist/run-dev-app.js +21 -3
- package/dist/scaffold-app.d.ts +3 -3
- package/dist/scaffold-app.js +125 -199
- package/dist/scaffold-deploy.d.ts +9 -0
- package/dist/scaffold-deploy.js +34 -6
- package/dist/scaffold-feature.js +1 -0
- package/package.json +18 -9
- package/src/changes.json +19 -0
- package/templates/managed/cache-cleanup.yml.template +30 -0
- package/templates/managed/ci.yml.template +65 -0
- package/templates/managed/husky-pre-push.template +36 -0
- package/templates/managed/kumiko-schema.ts.template +12 -0
- package/templates/managed/release.yml.template +55 -0
package/dist/build.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { ASSETS_DIR, type BuildManifest, type BuildProdBundleOptions, type BuildResult, buildProdBundle, type ClientEntry, type ClientEntryDeclaration, discoverHtmlTemplate, formatBuildResult, injectAssetTags, readClientEntriesConfig, resolveClientEntries, } from "@cosmicdrift/kumiko-server-runtime/build-prod-bundle";
|
|
2
|
-
export { type BuildServerBundleEntry, type BuildServerBundleOptions, type BuildServerBundleResult, buildServerBundle, discoverServerEntry, formatServerBuildResult, readExtraRuntimeExternals, } from "./build-server-bundle.
|
|
2
|
+
export { type BuildServerBundleEntry, type BuildServerBundleOptions, type BuildServerBundleResult, buildServerBundle, discoverServerEntry, formatServerBuildResult, readExtraRuntimeExternals, } from "./build-server-bundle.ts";
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { buildProdBundle, buildServerBundle, discoverServerEntry, formatBuildResult, formatServerBuildResult, readClientEntriesConfig, readExtraRuntimeExternals, resolveClientEntries, } from "./build.
|
|
2
|
-
export { createCrashTracker } from "./crash-tracker.
|
|
3
|
-
export { runInitDeployCli } from "./init-deploy-cli.
|
|
1
|
+
export { buildProdBundle, buildServerBundle, discoverServerEntry, formatBuildResult, formatServerBuildResult, readClientEntriesConfig, readExtraRuntimeExternals, resolveClientEntries, } from "./build.ts";
|
|
2
|
+
export { createCrashTracker } from "./crash-tracker.ts";
|
|
3
|
+
export { runInitDeployCli } from "./init-deploy-cli.ts";
|
package/dist/compose-stacks.d.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
import { type AccountSecurityFeatureOptions } from "@cosmicdrift/kumiko-bundled-features/account-security";
|
|
1
2
|
import { type AuthMfaFeatureOptions } from "@cosmicdrift/kumiko-bundled-features/auth-mfa";
|
|
3
|
+
import { type BillingFoundationOptions } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
4
|
+
import { type CreateCapOverviewOptions } from "@cosmicdrift/kumiko-bundled-features/cap-overview";
|
|
2
5
|
import { type LegalPagesOptions } from "@cosmicdrift/kumiko-bundled-features/legal-pages";
|
|
6
|
+
import { type SubscriptionMollieOptions } from "@cosmicdrift/kumiko-bundled-features/subscription-mollie";
|
|
7
|
+
import { type CreateTierEngineOptions } from "@cosmicdrift/kumiko-bundled-features/tier-engine";
|
|
3
8
|
import { type UserDataRightsOptions } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
9
|
+
import { type WaitlistOptions } from "@cosmicdrift/kumiko-bundled-features/waitlist";
|
|
4
10
|
import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
11
|
import { type MailBrandSuffixResolver, type MailFooterResolver } from "@cosmicdrift/kumiko-renderer-mail-html";
|
|
6
12
|
export type FileProviderKind = "inmemory" | "s3" | "s3-env";
|
|
7
13
|
export type MailTransportKind = "inmemory" | "smtp";
|
|
8
14
|
export type GdprStackOrder = "retention-first" | "compliance-first";
|
|
9
15
|
export type FileStackOptions = {
|
|
10
|
-
|
|
16
|
+
/** Without providers the stack needs runProdApp's `fileStorage` option. */
|
|
17
|
+
readonly providers?: readonly FileProviderKind[];
|
|
11
18
|
readonly includeFilesFeature?: boolean;
|
|
12
19
|
};
|
|
13
20
|
export type MailStackOptions = {
|
|
@@ -20,6 +27,11 @@ export type GdprStackOptions = {
|
|
|
20
27
|
readonly order?: GdprStackOrder;
|
|
21
28
|
readonly sessions?: boolean;
|
|
22
29
|
readonly tenantLifecycle?: boolean;
|
|
30
|
+
/** Adds sessions, user-data-rights and user-profile in the order the
|
|
31
|
+
* self-service privacy center needs; user-data-rights needs `mail`. */
|
|
32
|
+
readonly selfService?: {
|
|
33
|
+
readonly userDataRights?: UserDataRightsOptions;
|
|
34
|
+
};
|
|
23
35
|
/** Optional tokenVerifier provider(s) (e.g. PAT) when `sessions` is on.
|
|
24
36
|
* Session-only stacks need none — sessions registers sessionStore, which
|
|
25
37
|
* satisfies auth-foundation's boot check (#1570). Pass providers when the
|
|
@@ -56,12 +68,54 @@ export type RendererStackOptions = {
|
|
|
56
68
|
readonly mailBrandSuffix?: MailBrandSuffixResolver;
|
|
57
69
|
};
|
|
58
70
|
export declare function composeRendererStack(options?: RendererStackOptions): FeatureDefinition[];
|
|
71
|
+
/** Tenant mail transports reach users through channel-email, so the stack needs `mail`. */
|
|
59
72
|
export declare function composeMailStack(options: MailStackOptions): FeatureDefinition[];
|
|
60
|
-
export declare function composeFileStack(options
|
|
61
|
-
/** Retention + compliance (+ optional lifecycle/sessions).
|
|
73
|
+
export declare function composeFileStack(options?: FileStackOptions): FeatureDefinition[];
|
|
74
|
+
/** Retention + compliance (+ optional lifecycle/sessions/self-service). Needs an
|
|
75
|
+
* explicit KMS decision (`kmsMode`, or the low-level `kms` / `allowPlaintextPii`).
|
|
76
|
+
* `selfService` mounts user-profile, which requires user-data-rights-defaults and
|
|
77
|
+
* auth-email-password: composeUserDataRightsStack mounts the defaults, the login comes from the `auth` option. */
|
|
62
78
|
export declare function composeGdprStack(options?: GdprStackOptions): FeatureDefinition[];
|
|
63
79
|
export declare function composeUserDataRightsStack(options?: UserDataRightsStackOptions): FeatureDefinition[];
|
|
64
80
|
export declare function composeOpsStack(options?: OpsStackOptions): FeatureDefinition[];
|
|
65
81
|
/** Identity opt-ins: sessions by default; auth-mfa when `mfa` options given.
|
|
66
82
|
* Do not also pass `sessions: true` to composeGdprStack — duplicate feature. */
|
|
67
83
|
export declare function composeIdentityStack(options?: IdentityStackOptions): FeatureDefinition[];
|
|
84
|
+
export type AuthStackOptions = {
|
|
85
|
+
readonly sessions?: boolean;
|
|
86
|
+
readonly mfa?: AuthMfaFeatureOptions;
|
|
87
|
+
/** Self-service screen for MFA and own sessions; mounted when `mfa` and `sessions` are on. */
|
|
88
|
+
readonly accountSecurity?: AccountSecurityFeatureOptions;
|
|
89
|
+
};
|
|
90
|
+
/** auth-foundation + sessions, optional auth-mfa and account-security.
|
|
91
|
+
* auth-email-password stays with runProdApp's `auth` option, which also wires
|
|
92
|
+
* the MFA status checker into the login handler. */
|
|
93
|
+
export declare function composeAuthStack(options?: AuthStackOptions): FeatureDefinition[];
|
|
94
|
+
export type SaasStackBilling = {
|
|
95
|
+
readonly billing: "stripe";
|
|
96
|
+
} | {
|
|
97
|
+
readonly billing: "mollie";
|
|
98
|
+
readonly mollie: SubscriptionMollieOptions;
|
|
99
|
+
};
|
|
100
|
+
export type SaasStackOptions<TCaps extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>> = SaasStackBilling & {
|
|
101
|
+
readonly tiers: CreateTierEngineOptions<TCaps>;
|
|
102
|
+
readonly billingFoundation?: BillingFoundationOptions;
|
|
103
|
+
/** Mounts cap-counter and cap-overview. */
|
|
104
|
+
readonly caps?: CreateCapOverviewOptions;
|
|
105
|
+
/** Mounts waitlist; it needs auth-email-password and user-data-rights. */
|
|
106
|
+
readonly waitlist?: WaitlistOptions;
|
|
107
|
+
};
|
|
108
|
+
/** billing-foundation + tier-engine (+ caps, waitlist). `"stripe"` leaves
|
|
109
|
+
* subscription-stripe and its webhook route to runProdApp's `billing` option;
|
|
110
|
+
* `"mollie"` mounts subscription-mollie, whose webhook route the app adds.
|
|
111
|
+
* billing-foundation requires tenant-lifecycle and compliance-profiles, which
|
|
112
|
+
* composeGdprStack({ tenantLifecycle: true }) mounts. */
|
|
113
|
+
export declare function composeSaasStack<TCaps extends Readonly<Record<string, unknown>>>(options: SaasStackOptions<TCaps>): FeatureDefinition[];
|
|
114
|
+
export type SecurityStackOptions = {
|
|
115
|
+
/** Default true; pass false when another stack already mounts sessions with other options. */
|
|
116
|
+
readonly includeSessions?: boolean;
|
|
117
|
+
};
|
|
118
|
+
/** sessions, crypto-shredding, rate-limiting, audit: the security baseline the
|
|
119
|
+
* production boot warning checks. Relies on runProdApp's default L1/L2 rate
|
|
120
|
+
* limits and an explicit KMS decision. */
|
|
121
|
+
export declare function composeSecurityStack(options?: SecurityStackOptions): FeatureDefinition[];
|
package/dist/compose-stacks.js
CHANGED
|
@@ -5,12 +5,18 @@
|
|
|
5
5
|
// (kumiko-framework#2337).
|
|
6
6
|
//
|
|
7
7
|
// Composable SaaS stack presets — explicit opt-in blocks for run-config.ts.
|
|
8
|
-
// Presets export feature instances only; no implicit PAT scopes
|
|
9
|
-
//
|
|
8
|
+
// Presets export feature instances only; no implicit PAT scopes or
|
|
9
|
+
// anonymousAccess. A stack that needs a runProdApp boot option tags the
|
|
10
|
+
// feature that depends on it with `bootRequires`; runProdApp names the gap.
|
|
11
|
+
import { createAccountSecurityFeature, } from "@cosmicdrift/kumiko-bundled-features/account-security";
|
|
10
12
|
import { createAuditFeature } from "@cosmicdrift/kumiko-bundled-features/audit";
|
|
11
13
|
import { createAuthFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
12
14
|
import { createAuthMfaFeature, } from "@cosmicdrift/kumiko-bundled-features/auth-mfa";
|
|
15
|
+
import { createBillingFoundationFeature, } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
|
|
16
|
+
import { createCapCounterFeature } from "@cosmicdrift/kumiko-bundled-features/cap-counter";
|
|
17
|
+
import { createCapOverviewFeature, } from "@cosmicdrift/kumiko-bundled-features/cap-overview";
|
|
13
18
|
import { createComplianceProfilesFeature } from "@cosmicdrift/kumiko-bundled-features/compliance-profiles";
|
|
19
|
+
import { createCryptoShreddingFeature } from "@cosmicdrift/kumiko-bundled-features/crypto-shredding";
|
|
14
20
|
import { createDataRetentionFeature } from "@cosmicdrift/kumiko-bundled-features/data-retention";
|
|
15
21
|
import { createDeliveryFeature } from "@cosmicdrift/kumiko-bundled-features/delivery";
|
|
16
22
|
import { createFileFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/file-foundation";
|
|
@@ -25,11 +31,18 @@ import { createMailTransportSmtpFeature } from "@cosmicdrift/kumiko-bundled-feat
|
|
|
25
31
|
import { createRateLimitingFeature } from "@cosmicdrift/kumiko-bundled-features/rate-limiting";
|
|
26
32
|
import { createRendererFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/renderer-foundation";
|
|
27
33
|
import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";
|
|
34
|
+
import { createSubscriptionMollieFeature, } from "@cosmicdrift/kumiko-bundled-features/subscription-mollie";
|
|
28
35
|
import { createTemplateResolverFeature } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
29
36
|
import { createTenantLifecycleFeature } from "@cosmicdrift/kumiko-bundled-features/tenant-lifecycle";
|
|
37
|
+
import { createTierEngineFeature, } from "@cosmicdrift/kumiko-bundled-features/tier-engine";
|
|
30
38
|
import { createUserDataRightsFeature, } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
31
39
|
import { createUserDataRightsDefaultsFeature } from "@cosmicdrift/kumiko-bundled-features/user-data-rights-defaults";
|
|
40
|
+
import { createUserProfileFeature } from "@cosmicdrift/kumiko-bundled-features/user-profile";
|
|
41
|
+
import { createWaitlistFeature, } from "@cosmicdrift/kumiko-bundled-features/waitlist";
|
|
32
42
|
import { createRendererMailHtmlFeature, } from "@cosmicdrift/kumiko-renderer-mail-html";
|
|
43
|
+
function withBootRequires(feature, stack, options) {
|
|
44
|
+
return { ...feature, bootRequires: { stack, options } };
|
|
45
|
+
}
|
|
33
46
|
export function stackFeatureNames(features) {
|
|
34
47
|
return features.map((f) => f.name);
|
|
35
48
|
}
|
|
@@ -53,8 +66,11 @@ export function composeRendererStack(options = {}) {
|
|
|
53
66
|
}),
|
|
54
67
|
];
|
|
55
68
|
}
|
|
69
|
+
/** Tenant mail transports reach users through channel-email, so the stack needs `mail`. */
|
|
56
70
|
export function composeMailStack(options) {
|
|
57
|
-
const out = [
|
|
71
|
+
const out = [
|
|
72
|
+
withBootRequires(createMailFoundationFeature(), "composeMailStack", ["mail"]),
|
|
73
|
+
];
|
|
58
74
|
for (const transport of options.transports) {
|
|
59
75
|
if (transport === "inmemory")
|
|
60
76
|
out.push(createMailTransportInMemoryFeature());
|
|
@@ -63,9 +79,15 @@ export function composeMailStack(options) {
|
|
|
63
79
|
}
|
|
64
80
|
return out;
|
|
65
81
|
}
|
|
66
|
-
export function composeFileStack(options) {
|
|
67
|
-
const
|
|
68
|
-
|
|
82
|
+
export function composeFileStack(options = {}) {
|
|
83
|
+
const providers = options.providers ?? [];
|
|
84
|
+
const foundation = createFileFoundationFeature();
|
|
85
|
+
const out = [
|
|
86
|
+
providers.length === 0
|
|
87
|
+
? withBootRequires(foundation, "composeFileStack", ["fileStorage"])
|
|
88
|
+
: foundation,
|
|
89
|
+
];
|
|
90
|
+
for (const provider of providers) {
|
|
69
91
|
if (provider === "inmemory")
|
|
70
92
|
out.push(createFileProviderInMemoryFeature());
|
|
71
93
|
if (provider === "s3")
|
|
@@ -77,10 +99,13 @@ export function composeFileStack(options) {
|
|
|
77
99
|
out.push(createFilesFeature());
|
|
78
100
|
return out;
|
|
79
101
|
}
|
|
80
|
-
/** Retention + compliance (+ optional lifecycle/sessions).
|
|
102
|
+
/** Retention + compliance (+ optional lifecycle/sessions/self-service). Needs an
|
|
103
|
+
* explicit KMS decision (`kmsMode`, or the low-level `kms` / `allowPlaintextPii`).
|
|
104
|
+
* `selfService` mounts user-profile, which requires user-data-rights-defaults and
|
|
105
|
+
* auth-email-password: composeUserDataRightsStack mounts the defaults, the login comes from the `auth` option. */
|
|
81
106
|
export function composeGdprStack(options = {}) {
|
|
82
107
|
const order = options.order ?? "retention-first";
|
|
83
|
-
const retention = createDataRetentionFeature();
|
|
108
|
+
const retention = withBootRequires(createDataRetentionFeature(), "composeGdprStack", ["kmsMode"]);
|
|
84
109
|
const compliance = createComplianceProfilesFeature();
|
|
85
110
|
const out = order === "compliance-first" ? [compliance, retention] : [retention, compliance];
|
|
86
111
|
if (options.tenantLifecycle)
|
|
@@ -90,11 +115,19 @@ export function composeGdprStack(options = {}) {
|
|
|
90
115
|
if (options.providers)
|
|
91
116
|
out.push(...options.providers);
|
|
92
117
|
}
|
|
118
|
+
if (options.selfService) {
|
|
119
|
+
if (!options.sessions)
|
|
120
|
+
out.push(createSessionsFeature());
|
|
121
|
+
out.push(withBootRequires(createUserDataRightsFeature(options.selfService.userDataRights ?? {}), "composeGdprStack", ["mail"]), createUserProfileFeature());
|
|
122
|
+
}
|
|
93
123
|
return out;
|
|
94
124
|
}
|
|
95
125
|
export function composeUserDataRightsStack(options = {}) {
|
|
96
126
|
const includeDefaults = options.includeDefaults ?? true;
|
|
97
|
-
|
|
127
|
+
// Export-ready and deletion mails go through delivery + channel-email.
|
|
128
|
+
const out = [
|
|
129
|
+
withBootRequires(createUserDataRightsFeature(options.userDataRights ?? {}), "composeUserDataRightsStack", ["mail"]),
|
|
130
|
+
];
|
|
98
131
|
if (includeDefaults)
|
|
99
132
|
out.push(createUserDataRightsDefaultsFeature());
|
|
100
133
|
return out;
|
|
@@ -127,3 +160,49 @@ export function composeIdentityStack(options = {}) {
|
|
|
127
160
|
out.push(createAuthMfaFeature(options.mfa));
|
|
128
161
|
return out;
|
|
129
162
|
}
|
|
163
|
+
/** auth-foundation + sessions, optional auth-mfa and account-security.
|
|
164
|
+
* auth-email-password stays with runProdApp's `auth` option, which also wires
|
|
165
|
+
* the MFA status checker into the login handler. */
|
|
166
|
+
export function composeAuthStack(options = {}) {
|
|
167
|
+
const sessions = options.sessions ?? true;
|
|
168
|
+
const out = composeIdentityStack({
|
|
169
|
+
sessions,
|
|
170
|
+
...(options.mfa !== undefined && { mfa: options.mfa }),
|
|
171
|
+
});
|
|
172
|
+
if (options.mfa !== undefined && sessions) {
|
|
173
|
+
out.push(createAccountSecurityFeature(options.accountSecurity ?? {}));
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
/** billing-foundation + tier-engine (+ caps, waitlist). `"stripe"` leaves
|
|
178
|
+
* subscription-stripe and its webhook route to runProdApp's `billing` option;
|
|
179
|
+
* `"mollie"` mounts subscription-mollie, whose webhook route the app adds.
|
|
180
|
+
* billing-foundation requires tenant-lifecycle and compliance-profiles, which
|
|
181
|
+
* composeGdprStack({ tenantLifecycle: true }) mounts. */
|
|
182
|
+
export function composeSaasStack(options) {
|
|
183
|
+
const foundation = createBillingFoundationFeature(options.billingFoundation ?? {});
|
|
184
|
+
const out = [
|
|
185
|
+
options.billing === "stripe"
|
|
186
|
+
? withBootRequires(foundation, "composeSaasStack", ["billing"])
|
|
187
|
+
: foundation,
|
|
188
|
+
createTierEngineFeature(options.tiers),
|
|
189
|
+
];
|
|
190
|
+
if (options.billing === "mollie")
|
|
191
|
+
out.push(createSubscriptionMollieFeature(options.mollie));
|
|
192
|
+
if (options.caps)
|
|
193
|
+
out.push(createCapCounterFeature(), createCapOverviewFeature(options.caps));
|
|
194
|
+
if (options.waitlist)
|
|
195
|
+
out.push(createWaitlistFeature(options.waitlist));
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
/** sessions, crypto-shredding, rate-limiting, audit: the security baseline the
|
|
199
|
+
* production boot warning checks. Relies on runProdApp's default L1/L2 rate
|
|
200
|
+
* limits and an explicit KMS decision. */
|
|
201
|
+
export function composeSecurityStack(options = {}) {
|
|
202
|
+
return [
|
|
203
|
+
...(options.includeSessions === false ? [] : [createSessionsFeature()]),
|
|
204
|
+
withBootRequires(createCryptoShreddingFeature(), "composeSecurityStack", ["kmsMode"]),
|
|
205
|
+
withBootRequires(createRateLimitingFeature(), "composeSecurityStack", ["rateLimit"]),
|
|
206
|
+
createAuditFeature(),
|
|
207
|
+
];
|
|
208
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HostRoutingDispatchFn } from "@cosmicdrift/kumiko-bundled-features/host-routing";
|
|
2
|
+
import type { DevHostDispatch } from "./create-kumiko-server.ts";
|
|
3
|
+
export type ToDevHostDispatchOptions = {
|
|
4
|
+
readonly entries?: Readonly<Record<string, string>>;
|
|
5
|
+
readonly staticDir: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function toDevHostDispatch(dispatch: HostRoutingDispatchFn, options: ToDevHostDispatchOptions): DevHostDispatch;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
// Runs the prod host-routing decision in the dev server, so dev and prod
|
|
3
|
+
// cannot route differently. Per-host CSP is a prod concern and dropped here.
|
|
4
|
+
export function toDevHostDispatch(dispatch, options) {
|
|
5
|
+
const entries = options.entries ?? {};
|
|
6
|
+
const toDev = (result) => {
|
|
7
|
+
switch (result.kind) {
|
|
8
|
+
case "redirect":
|
|
9
|
+
return result;
|
|
10
|
+
case "html": {
|
|
11
|
+
const entryName = entries[result.file];
|
|
12
|
+
return entryName === undefined
|
|
13
|
+
? { kind: "static-html", file: join(options.staticDir, result.file) }
|
|
14
|
+
: { kind: "html", entryName };
|
|
15
|
+
}
|
|
16
|
+
case "not-found": {
|
|
17
|
+
if (result.file === undefined)
|
|
18
|
+
return { kind: "not-found" };
|
|
19
|
+
const entryName = entries[result.file];
|
|
20
|
+
return entryName === undefined
|
|
21
|
+
? { kind: "not-found", file: join(options.staticDir, result.file) }
|
|
22
|
+
: { kind: "not-found", entryName };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return async (req, deps) => {
|
|
27
|
+
const url = new URL(req.url);
|
|
28
|
+
const host = req.headers.get("host") ?? url.host;
|
|
29
|
+
return toDev(await dispatch({ host, path: url.pathname, search: url.search }, deps));
|
|
30
|
+
};
|
|
31
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
export { type ComposeFeaturesOptions, composeFeatures, } from "@cosmicdrift/kumiko-server-runtime/compose-features";
|
|
2
|
-
export { composeFileStack, composeGdprStack, composeIdentityStack, composeMailStack, composeOpsStack, composePagesStack, composeRendererStack, composeUserDataRightsStack, type FileProviderKind, type FileStackOptions, type GdprStackOptions, type GdprStackOrder, type IdentityStackOptions, type MailStackOptions, type MailTransportKind, type OpsStackOptions, type PagesStackOptions, stackFeatureNames, type UserDataRightsStackOptions, } from "./compose-stacks.
|
|
3
|
-
export { type CreateKumikoServerOptions, createKumikoServer, type KumikoServerHandle, PROD_BUNDLES_ENV, resolveStylesheet, STYLESHEET_WATCH_ENV, } from "./create-kumiko-server.
|
|
4
|
-
export { type FrameworkCoreEnv, frameworkCoreEnvSchema } from "./env-schema.
|
|
5
|
-
export type { AuthoringStyle, BuildFewShotCorpusOptions, CorpusWarning, FewShotCorpus, FewShotEntry, } from "./few-shot-corpus.
|
|
6
|
-
export { buildFewShotCorpus, pathToId } from "./few-shot-corpus.
|
|
7
|
-
export { resolveFrameworkVersion } from "./framework-version.
|
|
8
|
-
export type
|
|
9
|
-
export {
|
|
10
|
-
export
|
|
11
|
-
export {
|
|
12
|
-
export
|
|
13
|
-
export {
|
|
14
|
-
export
|
|
15
|
-
export {
|
|
16
|
-
export
|
|
17
|
-
export {
|
|
18
|
-
export
|
|
19
|
-
export {
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
2
|
+
export { type AuthStackOptions, composeAuthStack, composeFileStack, composeGdprStack, composeIdentityStack, composeMailStack, composeOpsStack, composePagesStack, composeRendererStack, composeSaasStack, composeSecurityStack, composeUserDataRightsStack, type FileProviderKind, type FileStackOptions, type GdprStackOptions, type GdprStackOrder, type IdentityStackOptions, type MailStackOptions, type MailTransportKind, type OpsStackOptions, type PagesStackOptions, type SaasStackBilling, type SaasStackOptions, type SecurityStackOptions, stackFeatureNames, type UserDataRightsStackOptions, } from "./compose-stacks.ts";
|
|
3
|
+
export { type CreateKumikoServerOptions, createKumikoServer, type KumikoServerHandle, PROD_BUNDLES_ENV, resolveStylesheet, STYLESHEET_WATCH_ENV, } from "./create-kumiko-server.ts";
|
|
4
|
+
export { type FrameworkCoreEnv, frameworkCoreEnvSchema } from "./env-schema.ts";
|
|
5
|
+
export type { AuthoringStyle, BuildFewShotCorpusOptions, CorpusWarning, FewShotCorpus, FewShotEntry, } from "./few-shot-corpus.ts";
|
|
6
|
+
export { buildFewShotCorpus, pathToId } from "./few-shot-corpus.ts";
|
|
7
|
+
export { resolveFrameworkVersion } from "./framework-version.ts";
|
|
8
|
+
export { type ToDevHostDispatchOptions, toDevHostDispatch } from "./host-dispatch-adapter.ts";
|
|
9
|
+
export type { CliOutput, RunInitDeployCliOptions } from "./init-deploy-cli.ts";
|
|
10
|
+
export { runInitDeployCli } from "./init-deploy-cli.ts";
|
|
11
|
+
export type { RunDevAppAuthOptions, RunDevAppOptions, SeedFn } from "./run-dev-app.ts";
|
|
12
|
+
export { runDevApp } from "./run-dev-app.ts";
|
|
13
|
+
export type { ScaffoldAppOptions, ScaffoldAppResult, ScaffoldFeatureEntry, } from "./scaffold-app.ts";
|
|
14
|
+
export { SCAFFOLD_BIOME_VERSION, scaffoldApp } from "./scaffold-app.ts";
|
|
15
|
+
export type { ScaffoldAppFeatureOptions, ScaffoldAppFeatureResult, } from "./scaffold-app-feature.ts";
|
|
16
|
+
export { runConfigPathForApp, scaffoldAppFeature } from "./scaffold-app-feature.ts";
|
|
17
|
+
export type { CheckDeployDriftResult, DeployDriftEntry, RenderDeployFilesOptions, RenderDeployFilesResult, RenderedDeployFile, ScaffoldDeployDetected, ScaffoldDeployOptions, ScaffoldDeployResult, ScaffoldedFile, } from "./scaffold-deploy.ts";
|
|
18
|
+
export { checkDeployDrift, renderDeployFiles, scaffoldDeploy } from "./scaffold-deploy.ts";
|
|
19
|
+
export type { ScaffoldFeatureOptions, ScaffoldFeatureResult } from "./scaffold-feature.ts";
|
|
20
|
+
export { scaffoldFeature } from "./scaffold-feature.ts";
|
|
21
|
+
export { type SetupTestStackFromFeaturesOptions, setupTestStackFromFeatures, type TestStackPreset, } from "./setup-test-stack-from-features.ts";
|
|
22
|
+
export { renderWelcomeBanner, type WelcomeBannerInput } from "./welcome-banner.ts";
|
package/dist/index.js
CHANGED
|
@@ -17,11 +17,12 @@ export { composeFeatures, } from "@cosmicdrift/kumiko-server-runtime/compose-fea
|
|
|
17
17
|
// im Sub-Path-Export `@cosmicdrift/kumiko-dev-server/build`. Damit zieht der Main-Barrel
|
|
18
18
|
// kein Bun-Toolchain-Bundle mehr in Production-Reads (z.B. wenn drizzle-kit
|
|
19
19
|
// die App-Config unter Node lädt).
|
|
20
|
-
export { composeFileStack, composeGdprStack, composeIdentityStack, composeMailStack, composeOpsStack, composePagesStack, composeRendererStack, composeUserDataRightsStack, stackFeatureNames, } from "./compose-stacks.js";
|
|
20
|
+
export { composeAuthStack, composeFileStack, composeGdprStack, composeIdentityStack, composeMailStack, composeOpsStack, composePagesStack, composeRendererStack, composeSaasStack, composeSecurityStack, composeUserDataRightsStack, stackFeatureNames, } from "./compose-stacks.js";
|
|
21
21
|
export { createKumikoServer, PROD_BUNDLES_ENV, resolveStylesheet, STYLESHEET_WATCH_ENV, } from "./create-kumiko-server.js";
|
|
22
22
|
export { frameworkCoreEnvSchema } from "./env-schema.js";
|
|
23
23
|
export { buildFewShotCorpus, pathToId } from "./few-shot-corpus.js";
|
|
24
24
|
export { resolveFrameworkVersion } from "./framework-version.js";
|
|
25
|
+
export { toDevHostDispatch } from "./host-dispatch-adapter.js";
|
|
25
26
|
export { runInitDeployCli } from "./init-deploy-cli.js";
|
|
26
27
|
export { runDevApp } from "./run-dev-app.js";
|
|
27
28
|
export { SCAFFOLD_BIOME_VERSION, scaffoldApp } from "./scaffold-app.js";
|
package/dist/init-deploy-cli.js
CHANGED
|
@@ -8,8 +8,13 @@ import { getFlag, getNumberFlag, getStringFlag, parseArgs, } from "@cosmicdrift/
|
|
|
8
8
|
import * as z from "zod";
|
|
9
9
|
import { checkDeployDrift, scaffoldDeploy } from "./scaffold-deploy.js";
|
|
10
10
|
const USAGE = "Usage: kumiko-init-deploy --app <name> [--port <n>] [--github-org <org>] [--out <dir>] [--force | --check]";
|
|
11
|
+
// Kept for one release so existing pipelines keep running; deploy/ is now a
|
|
12
|
+
// managed-files group that `kumiko new app` writes and `kumiko sync-managed` updates.
|
|
13
|
+
const DEPRECATION_NOTICE = " ! kumiko-init-deploy is deprecated and will be removed in the next release: deploy/ files are managed files now. Use `kumiko check managed` and `kumiko sync-managed --write`.";
|
|
11
14
|
const HELP = `${USAGE}
|
|
12
15
|
|
|
16
|
+
${DEPRECATION_NOTICE}
|
|
17
|
+
|
|
13
18
|
--app <name> app name (default: package.json "name" without its @scope/)
|
|
14
19
|
--port <n> port the container exposes
|
|
15
20
|
--github-org <org> GitHub org for the image reference
|
|
@@ -87,6 +92,7 @@ export async function runInitDeployCli({ argv, cwd, out, }) {
|
|
|
87
92
|
out.log(HELP);
|
|
88
93
|
return 0;
|
|
89
94
|
}
|
|
95
|
+
out.err(DEPRECATION_NOTICE);
|
|
90
96
|
const args = parseArgs(argv);
|
|
91
97
|
const force = getFlag(args, "force");
|
|
92
98
|
const check = getFlag(args, "check");
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const STANDARD_APP_SCRIPTS: readonly ["dev", "build", "start", "typecheck", "lint", "check", "test", "test:unit", "test:integration", "test:integration:ci", "test:dom", "test:real", "e2e", "e2e:real", "screenshots", "prepare"];
|
|
2
|
+
export type StandardAppScript = (typeof STANDARD_APP_SCRIPTS)[number];
|
|
3
|
+
/** Extras every app may carry; they are listed but expected. */
|
|
4
|
+
export declare const KNOWN_EXTRA_APP_SCRIPTS: readonly ["test:verbose", "test:bunfig", "test:lib-coverage", "shots"];
|
|
5
|
+
export type AppScriptsReport = {
|
|
6
|
+
readonly missing: readonly StandardAppScript[];
|
|
7
|
+
readonly knownExtras: readonly string[];
|
|
8
|
+
readonly appExtras: readonly string[];
|
|
9
|
+
};
|
|
10
|
+
export declare function checkAppScripts(scripts: Readonly<Record<string, string>>, options: {
|
|
11
|
+
readonly hasUi: boolean;
|
|
12
|
+
}): AppScriptsReport;
|
|
13
|
+
export declare const PREPARE_SCRIPT = "[ \"$HUSKY\" = \"0\" ] || git config core.hooksPath .husky 2>/dev/null || true";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// The package.json scripts every app exposes, so agents and CI call the same
|
|
2
|
+
// names in every repo.
|
|
3
|
+
export const STANDARD_APP_SCRIPTS = [
|
|
4
|
+
"dev",
|
|
5
|
+
"build",
|
|
6
|
+
"start",
|
|
7
|
+
"typecheck",
|
|
8
|
+
"lint",
|
|
9
|
+
"check",
|
|
10
|
+
"test",
|
|
11
|
+
"test:unit",
|
|
12
|
+
"test:integration",
|
|
13
|
+
"test:integration:ci",
|
|
14
|
+
"test:dom",
|
|
15
|
+
"test:real",
|
|
16
|
+
"e2e",
|
|
17
|
+
"e2e:real",
|
|
18
|
+
"screenshots",
|
|
19
|
+
"prepare",
|
|
20
|
+
];
|
|
21
|
+
/** Extras every app may carry; they are listed but expected. */
|
|
22
|
+
export const KNOWN_EXTRA_APP_SCRIPTS = [
|
|
23
|
+
"test:verbose",
|
|
24
|
+
"test:bunfig",
|
|
25
|
+
"test:lib-coverage",
|
|
26
|
+
"shots",
|
|
27
|
+
];
|
|
28
|
+
export function checkAppScripts(scripts, options) {
|
|
29
|
+
const required = STANDARD_APP_SCRIPTS.filter((name) => name !== "test:dom" || options.hasUi);
|
|
30
|
+
const standard = new Set(STANDARD_APP_SCRIPTS);
|
|
31
|
+
const known = new Set(KNOWN_EXTRA_APP_SCRIPTS);
|
|
32
|
+
const extras = Object.keys(scripts).filter((name) => !standard.has(name));
|
|
33
|
+
return {
|
|
34
|
+
missing: required.filter((name) => scripts[name] === undefined),
|
|
35
|
+
knownExtras: extras.filter((name) => known.has(name)),
|
|
36
|
+
appExtras: extras.filter((name) => !known.has(name)),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// The hooks path line every app already carries; HUSKY=0 (CI) skips it.
|
|
40
|
+
export const PREPARE_SCRIPT = '[ "$HUSKY" = "0" ] || git config core.hooksPath .husky 2>/dev/null || true';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ManagedAppFacts, type ManagedFile } from "./registry.ts";
|
|
2
|
+
export type ManagedFileState = {
|
|
3
|
+
readonly state: "ok";
|
|
4
|
+
} | {
|
|
5
|
+
readonly state: "missing";
|
|
6
|
+
}
|
|
7
|
+
/** `-` lines: template, `+` lines: repo. */
|
|
8
|
+
| {
|
|
9
|
+
readonly state: "differs";
|
|
10
|
+
readonly diff: string;
|
|
11
|
+
}
|
|
12
|
+
/** Exists without the marker; `diff` is set when the content also differs. */
|
|
13
|
+
| {
|
|
14
|
+
readonly state: "unmarked";
|
|
15
|
+
readonly diff?: string;
|
|
16
|
+
} | {
|
|
17
|
+
readonly state: "local";
|
|
18
|
+
readonly reason: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly state: "invalid";
|
|
21
|
+
readonly message: string;
|
|
22
|
+
};
|
|
23
|
+
export type ManagedFileReport = ManagedFileState & {
|
|
24
|
+
readonly path: string;
|
|
25
|
+
readonly kind: ManagedFile["kind"];
|
|
26
|
+
};
|
|
27
|
+
export type ManagedCheckResult = {
|
|
28
|
+
/** kumiko.config.ts calls defineAppConfig: drift fails the check from then on. */
|
|
29
|
+
readonly adopted: boolean;
|
|
30
|
+
readonly files: readonly ManagedFileReport[];
|
|
31
|
+
};
|
|
32
|
+
export declare function checkManagedFiles(facts: ManagedAppFacts): ManagedCheckResult;
|
|
33
|
+
/** States that fail `kumiko check managed` once the app has adopted kumiko.config.ts. */
|
|
34
|
+
export declare function isManagedDrift(report: ManagedFileReport): boolean;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { mergeBunfig } from "@cosmicdrift/kumiko-testing/bunfig";
|
|
4
|
+
import { parseJsonc } from "./jsonc.js";
|
|
5
|
+
import { renderLineDiff } from "./line-diff.js";
|
|
6
|
+
import { readManagedMarker, stripManagedMarker } from "./marker.js";
|
|
7
|
+
import { BIOME_PRESET, listManagedFiles, renderManagedBunfig, TSCONFIG_PRESET, } from "./registry.js";
|
|
8
|
+
function readIfExists(path) {
|
|
9
|
+
return existsSync(path) ? readFileSync(path, "utf-8") : undefined;
|
|
10
|
+
}
|
|
11
|
+
function compareBodies(expected, actual) {
|
|
12
|
+
return expected === actual ? undefined : renderLineDiff(expected, actual);
|
|
13
|
+
}
|
|
14
|
+
function checkTemplate(file, existing) {
|
|
15
|
+
const marker = readManagedMarker(existing);
|
|
16
|
+
if (marker.kind === "invalid")
|
|
17
|
+
return { state: "invalid", message: marker.message };
|
|
18
|
+
if (marker.kind === "local")
|
|
19
|
+
return { state: "local", reason: marker.reason };
|
|
20
|
+
const diff = compareBodies(stripManagedMarker(file.content), stripManagedMarker(existing));
|
|
21
|
+
if (marker.kind === "unmarked")
|
|
22
|
+
return diff === undefined ? { state: "unmarked" } : { state: "unmarked", diff };
|
|
23
|
+
return diff === undefined ? { state: "ok" } : { state: "differs", diff };
|
|
24
|
+
}
|
|
25
|
+
function checkBunfig(file, existing) {
|
|
26
|
+
const marker = readManagedMarker(existing);
|
|
27
|
+
if (marker.kind === "invalid")
|
|
28
|
+
return { state: "invalid", message: marker.message };
|
|
29
|
+
if (marker.kind === "local")
|
|
30
|
+
return { state: "local", reason: marker.reason };
|
|
31
|
+
const merged = mergeBunfig(renderManagedBunfig(file, existing), existing);
|
|
32
|
+
if (!merged.ok) {
|
|
33
|
+
const keys = merged.unknownKeys.map(({ section, key }) => `[${section}] ${key}`).join(", ");
|
|
34
|
+
return { state: "invalid", message: `keys the generator does not own: ${keys}` };
|
|
35
|
+
}
|
|
36
|
+
const diff = compareBodies(merged.content, existing);
|
|
37
|
+
if (marker.kind === "unmarked")
|
|
38
|
+
return diff === undefined ? { state: "unmarked" } : { state: "unmarked", diff };
|
|
39
|
+
return diff === undefined ? { state: "ok" } : { state: "differs", diff };
|
|
40
|
+
}
|
|
41
|
+
function extendsList(value) {
|
|
42
|
+
if (typeof value !== "object" || value === null || !("extends" in value))
|
|
43
|
+
return [];
|
|
44
|
+
const extendsValue = value.extends;
|
|
45
|
+
return Array.isArray(extendsValue) ? extendsValue : [extendsValue];
|
|
46
|
+
}
|
|
47
|
+
function checkStructural(file, facts, existing) {
|
|
48
|
+
if (file.path === "kumiko.config.ts") {
|
|
49
|
+
switch (facts.config.kind) {
|
|
50
|
+
case "defined":
|
|
51
|
+
return { state: "ok" };
|
|
52
|
+
case "legacy":
|
|
53
|
+
return {
|
|
54
|
+
state: "invalid",
|
|
55
|
+
message: "default-export defineAppConfig({ features, client, ports }) from @cosmicdrift/kumiko-framework/config",
|
|
56
|
+
};
|
|
57
|
+
case "invalid":
|
|
58
|
+
return { state: "invalid", message: facts.config.message };
|
|
59
|
+
case "missing":
|
|
60
|
+
return { state: "missing" };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const preset = file.path === "biome.json" ? BIOME_PRESET : TSCONFIG_PRESET;
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = parseJsonc(existing, file.path);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return {
|
|
70
|
+
state: "invalid",
|
|
71
|
+
message: `cannot parse: ${error instanceof Error ? error.message : String(error)}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return extendsList(parsed).includes(preset)
|
|
75
|
+
? { state: "ok" }
|
|
76
|
+
: { state: "invalid", message: `must extend "${preset}"; keep app overrides below extends` };
|
|
77
|
+
}
|
|
78
|
+
function checkFile(file, facts) {
|
|
79
|
+
if (file.kind === "structural" && file.path === "kumiko.config.ts") {
|
|
80
|
+
return checkStructural(file, facts, "");
|
|
81
|
+
}
|
|
82
|
+
const existing = readIfExists(join(facts.appRoot, file.path));
|
|
83
|
+
if (existing === undefined)
|
|
84
|
+
return { state: "missing" };
|
|
85
|
+
switch (file.kind) {
|
|
86
|
+
case "template":
|
|
87
|
+
return checkTemplate(file, existing);
|
|
88
|
+
case "bunfig":
|
|
89
|
+
return checkBunfig(file, existing);
|
|
90
|
+
case "structural":
|
|
91
|
+
return checkStructural(file, facts, existing);
|
|
92
|
+
case "seed":
|
|
93
|
+
return { state: "ok" };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function checkManagedFiles(facts) {
|
|
97
|
+
return {
|
|
98
|
+
adopted: facts.config.kind === "defined",
|
|
99
|
+
files: listManagedFiles(facts).map((file) => ({
|
|
100
|
+
path: file.path,
|
|
101
|
+
kind: file.kind,
|
|
102
|
+
...checkFile(file, facts),
|
|
103
|
+
})),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** States that fail `kumiko check managed` once the app has adopted kumiko.config.ts. */
|
|
107
|
+
export function isManagedDrift(report) {
|
|
108
|
+
return report.state !== "ok" && report.state !== "local";
|
|
109
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { listAppPorts } from "@cosmicdrift/kumiko-framework/config";
|
|
2
|
+
export { type AppScriptsReport, checkAppScripts, KNOWN_EXTRA_APP_SCRIPTS, PREPARE_SCRIPT, STANDARD_APP_SCRIPTS, type StandardAppScript, } from "./app-scripts.ts";
|
|
3
|
+
export { checkManagedFiles, isManagedDrift, type ManagedCheckResult, type ManagedFileReport, type ManagedFileState, } from "./check.ts";
|
|
4
|
+
export { addManagedMarker, MANAGED_MARKER, readManagedMarker, stripManagedMarker, } from "./marker.ts";
|
|
5
|
+
export { findPortCollisions, type PortClaim, type PortCollision, type ScannedApp, scanWorkspaceApps, } from "./port-registry.ts";
|
|
6
|
+
export { BIOME_PRESET, listManagedFiles, type ManagedAppFacts, type ManagedAppInput, type ManagedFile, type ManagedTemplateFile, renderBiomePresetJson, renderManagedBunfig, renderManagedTemplates, renderTsconfigPresetJson, resolveManagedAppFacts, TSCONFIG_PRESET, } from "./registry.ts";
|
|
7
|
+
export { parseStaticAppConfig, readStaticAppConfig, type StaticAppConfig, } from "./static-app-config.ts";
|
|
8
|
+
export { type SyncAction, type SyncManagedOptions, syncManagedFiles } from "./sync.ts";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { listAppPorts } from "@cosmicdrift/kumiko-framework/config";
|
|
2
|
+
export { checkAppScripts, KNOWN_EXTRA_APP_SCRIPTS, PREPARE_SCRIPT, STANDARD_APP_SCRIPTS, } from "./app-scripts.js";
|
|
3
|
+
export { checkManagedFiles, isManagedDrift, } from "./check.js";
|
|
4
|
+
export { addManagedMarker, MANAGED_MARKER, readManagedMarker, stripManagedMarker, } from "./marker.js";
|
|
5
|
+
export { findPortCollisions, scanWorkspaceApps, } from "./port-registry.js";
|
|
6
|
+
export { BIOME_PRESET, listManagedFiles, renderBiomePresetJson, renderManagedBunfig, renderManagedTemplates, renderTsconfigPresetJson, resolveManagedAppFacts, TSCONFIG_PRESET, } from "./registry.js";
|
|
7
|
+
export { parseStaticAppConfig, readStaticAppConfig, } from "./static-app-config.js";
|
|
8
|
+
export { syncManagedFiles } from "./sync.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseJsonc(source: string, context: string): unknown;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { parseJsonOrThrow } from "@cosmicdrift/kumiko-framework/utils";
|
|
2
|
+
// Strings come first in each alternation, so comment and comma patterns
|
|
3
|
+
// inside string literals are matched as part of the string and kept.
|
|
4
|
+
const STRING_OR_COMMENT = /"(?:\\.|[^"\\])*"|\/\/[^\n]*|\/\*[\s\S]*?\*\//g;
|
|
5
|
+
const STRING_OR_TRAILING_COMMA = /"(?:\\.|[^"\\])*"|,(\s*[}\]])/g;
|
|
6
|
+
// biome.json and tsconfig.json accept comments and trailing commas; strip both
|
|
7
|
+
// (outside strings) so they parse as JSON.
|
|
8
|
+
export function parseJsonc(source, context) {
|
|
9
|
+
const withoutComments = source.replace(STRING_OR_COMMENT, (match) => match.startsWith('"') ? match : "");
|
|
10
|
+
const withoutTrailingCommas = withoutComments.replace(STRING_OR_TRAILING_COMMA, (match, afterComma) => afterComma ?? match);
|
|
11
|
+
return parseJsonOrThrow(withoutTrailingCommas, context);
|
|
12
|
+
}
|