@forgerock/login-framework-cli 0.0.0-beta.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/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/commands/generate.d.ts +28 -0
- package/dist/commands/generate.js +137 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +95 -0
- package/dist/commands/releases.d.ts +3 -0
- package/dist/commands/releases.js +12 -0
- package/dist/commands/source.d.ts +22 -0
- package/dist/commands/source.js +24 -0
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.js +36 -0
- package/dist/config/exclusions.d.ts +1 -0
- package/dist/config/exclusions.js +62 -0
- package/dist/config/version.d.ts +26 -0
- package/dist/config/version.js +41 -0
- package/dist/errors.d.ts +90 -0
- package/dist/errors.js +25 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +34 -0
- package/dist/services/file-system.d.ts +13 -0
- package/dist/services/file-system.js +64 -0
- package/dist/services/registry.d.ts +22 -0
- package/dist/services/registry.js +169 -0
- package/dist/services/release.d.ts +27 -0
- package/dist/services/release.js +86 -0
- package/dist/templates/callback/__COMPONENT_SLUG__.svelte +73 -0
- package/dist/templates/callback/__COMPONENT_SLUG__.utilities.test.ts +9 -0
- package/dist/templates/callback/__COMPONENT_SLUG__.utilities.ts +13 -0
- package/dist/templates/stage/__COMPONENT_SLUG__.svelte +148 -0
- package/dist/templates/stage/__COMPONENT_SLUG__.utilities.test.ts +9 -0
- package/dist/templates/stage/__COMPONENT_SLUG__.utilities.ts +13 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +4 -0
- package/package.json +57 -0
- package/scripts/generate-registry.mjs +23 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Schema } from 'effect';
|
|
2
|
+
import { FileSystem, HttpClient, HttpClientResponse } from '@effect/platform';
|
|
3
|
+
import { NodeHttpClient } from '@effect/platform-node';
|
|
4
|
+
import { extract } from 'tar';
|
|
5
|
+
import { InvalidVersionError, ReleaseFsError, ReleaseNetworkError, ReleaseNotFoundError, ReleaseParseError, } from '../errors.js';
|
|
6
|
+
const REPO = 'ForgeRock/forgerock-web-login-framework';
|
|
7
|
+
const API_HEADERS = {
|
|
8
|
+
'User-Agent': 'ping-lf-cli',
|
|
9
|
+
Accept: 'application/vnd.github.v3+json',
|
|
10
|
+
};
|
|
11
|
+
const VERSION_REGEX = /^v?\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
12
|
+
const toCauseString = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
13
|
+
export function validateVersion(version) {
|
|
14
|
+
return VERSION_REGEX.test(version)
|
|
15
|
+
? Effect.succeed(version)
|
|
16
|
+
: Effect.fail(new InvalidVersionError({ version }));
|
|
17
|
+
}
|
|
18
|
+
const GithubReleaseSchema = Schema.Struct({
|
|
19
|
+
tag_name: Schema.String,
|
|
20
|
+
published_at: Schema.String,
|
|
21
|
+
draft: Schema.Boolean,
|
|
22
|
+
prerelease: Schema.Boolean,
|
|
23
|
+
});
|
|
24
|
+
const decodeGithubReleases = Schema.decodeUnknown(Schema.parseJson(Schema.Array(GithubReleaseSchema)));
|
|
25
|
+
/**
|
|
26
|
+
* Parses a GitHub releases API JSON response and returns an array of
|
|
27
|
+
* `{ tag, publishedAt }` objects, excluding drafts and pre-releases.
|
|
28
|
+
*/
|
|
29
|
+
export function parseReleaseTags(json) {
|
|
30
|
+
return decodeGithubReleases(json).pipe(Effect.map((releases) => releases
|
|
31
|
+
.filter((r) => !r.draft && !r.prerelease)
|
|
32
|
+
.map((r) => ({ tag: r.tag_name, publishedAt: r.published_at.slice(0, 10) }))), Effect.mapError((cause) => new ReleaseParseError({ cause: toCauseString(cause) })));
|
|
33
|
+
}
|
|
34
|
+
export class Release extends Context.Tag('Release')() {
|
|
35
|
+
}
|
|
36
|
+
const LatestReleaseSchema = Schema.Struct({ tag_name: Schema.String });
|
|
37
|
+
const decodeLatestRelease = Schema.decodeUnknown(Schema.parseJson(LatestReleaseSchema));
|
|
38
|
+
const downloadAndExtract = (http, url, targetDir) => Effect.gen(function* () {
|
|
39
|
+
const fs = yield* FileSystem.FileSystem;
|
|
40
|
+
const tempDir = `${targetDir}/.framework-tmp`;
|
|
41
|
+
const tarPath = `${tempDir}/release.tar.gz`;
|
|
42
|
+
return yield* Effect.acquireRelease(Effect.gen(function* () {
|
|
43
|
+
yield* fs.makeDirectory(tempDir, { recursive: true }).pipe(Effect.mapError((cause) => new ReleaseFsError({
|
|
44
|
+
operation: 'makeDirectory',
|
|
45
|
+
cause: toCauseString(cause),
|
|
46
|
+
})));
|
|
47
|
+
const buffer = yield* HttpClient.followRedirects(http)
|
|
48
|
+
.get(url, { headers: { 'User-Agent': 'ping-lf-cli' } })
|
|
49
|
+
.pipe(Effect.flatMap(HttpClientResponse.filterStatusOk), Effect.flatMap((res) => res.arrayBuffer), Effect.mapError((cause) => new ReleaseNetworkError({ cause: toCauseString(cause) })));
|
|
50
|
+
yield* fs
|
|
51
|
+
.writeFile(tarPath, new Uint8Array(buffer))
|
|
52
|
+
.pipe(Effect.mapError((cause) => new ReleaseFsError({ operation: 'writeFile', cause: toCauseString(cause) })));
|
|
53
|
+
yield* Effect.tryPromise({
|
|
54
|
+
try: () => extract({ file: tarPath, cwd: tempDir, strip: 1 }),
|
|
55
|
+
catch: (cause) => new ReleaseParseError({ cause: toCauseString(cause) }),
|
|
56
|
+
});
|
|
57
|
+
return tempDir;
|
|
58
|
+
}), (dir) => fs.remove(dir, { recursive: true }).pipe(Effect.ignore));
|
|
59
|
+
});
|
|
60
|
+
const buildGithubReleaseLayer = Layer.effect(Release, Effect.gen(function* () {
|
|
61
|
+
const http = yield* HttpClient.HttpClient;
|
|
62
|
+
return {
|
|
63
|
+
archiveUrl: (version) => `https://github.com/${REPO}/archive/refs/tags/${version}.tar.gz`,
|
|
64
|
+
resolveLatest: () => http
|
|
65
|
+
.get(`https://api.github.com/repos/${REPO}/releases/latest`, { headers: API_HEADERS })
|
|
66
|
+
.pipe(Effect.flatMap(HttpClientResponse.filterStatusOk), Effect.flatMap((res) => res.text), Effect.mapError((cause) => new ReleaseNetworkError({ cause: toCauseString(cause) })), Effect.flatMap((text) => decodeLatestRelease(text).pipe(Effect.mapError((cause) => new ReleaseParseError({ cause: toCauseString(cause) })))), Effect.map((data) => data.tag_name)),
|
|
67
|
+
listReleases: () => http
|
|
68
|
+
.get(`https://api.github.com/repos/${REPO}/releases?per_page=20`, {
|
|
69
|
+
headers: API_HEADERS,
|
|
70
|
+
})
|
|
71
|
+
.pipe(Effect.flatMap(HttpClientResponse.filterStatusOk), Effect.flatMap((res) => res.text), Effect.mapError((cause) => new ReleaseNetworkError({ cause: toCauseString(cause) })), Effect.flatMap((json) => parseReleaseTags(json)), Effect.flatMap((releases) => releases.length === 0
|
|
72
|
+
? Effect.fail(new ReleaseNotFoundError({ cause: 'No releases found on GitHub' }))
|
|
73
|
+
: Effect.succeed(releases))),
|
|
74
|
+
fetch: (version, targetDir) => Effect.gen(function* () {
|
|
75
|
+
yield* validateVersion(version);
|
|
76
|
+
const url = `https://github.com/${REPO}/archive/refs/tags/${version}.tar.gz`;
|
|
77
|
+
return yield* downloadAndExtract(http, url, targetDir);
|
|
78
|
+
}),
|
|
79
|
+
fetchBranch: (branch, targetDir) => {
|
|
80
|
+
const url = `https://github.com/${REPO}/archive/refs/heads/${branch}.tar.gz`;
|
|
81
|
+
return downloadAndExtract(http, url, targetDir);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}));
|
|
85
|
+
export const makeGithubReleaseLayer = (httpLayer) => buildGithubReleaseLayer.pipe(Layer.provide(httpLayer));
|
|
86
|
+
export const GithubReleaseLayer = makeGithubReleaseLayer(NodeHttpClient.layer);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
Type: callback
|
|
4
|
+
Name: __COMPONENT_NAME__
|
|
5
|
+
|
|
6
|
+
Custom callback component. Replace this description with your own.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import type { FRCallback } from '@forgerock/javascript-sdk';
|
|
11
|
+
import type { z } from 'zod';
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
CallbackMetadata,
|
|
15
|
+
SelfSubmitFunction,
|
|
16
|
+
StepMetadata,
|
|
17
|
+
} from '$journey/journey.interfaces';
|
|
18
|
+
import type { styleSchema } from '$core/style.store';
|
|
19
|
+
import type { Maybe } from '$core/interfaces';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The AM callback instance for this component. Use `callback.getInputValue()`
|
|
23
|
+
* and `callback.setInputValue()` to read/write values sent back to the server.
|
|
24
|
+
*/
|
|
25
|
+
export let callback: FRCallback;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Optional function to trigger self-submission (e.g. after an async action).
|
|
29
|
+
* Set to `null` when the callback does not need to submit the form itself.
|
|
30
|
+
*/
|
|
31
|
+
export const selfSubmitFunction: Maybe<SelfSubmitFunction> = null;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Metadata about the current step (page node) — includes stage name,
|
|
35
|
+
* header/description overrides, and derived helpers like `isStepSelfSubmittable()`.
|
|
36
|
+
*/
|
|
37
|
+
export const stepMetadata: Maybe<StepMetadata> = null;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Per-callback metadata from the step — may include policies, failed policies,
|
|
41
|
+
* and other AM-provided hints for rendering.
|
|
42
|
+
*/
|
|
43
|
+
export const callbackMetadata: Maybe<CallbackMetadata> = null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The widget's resolved style configuration (colors, logos, labels, etc.).
|
|
47
|
+
* Use this to keep your custom callback visually consistent with the theme.
|
|
48
|
+
*/
|
|
49
|
+
export const style: z.infer<typeof styleSchema> = {};
|
|
50
|
+
|
|
51
|
+
// Suppress the "unused export" warning — remove `void` once you use `callback`.
|
|
52
|
+
void callback;
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<!-- Replace the markup below with your custom callback UI. -->
|
|
56
|
+
<div class="__COMPONENT_SLUG__ tw_p-4 tw_rounded-lg tw_border tw_border-secondary-light dark:tw_border-secondary-dark">
|
|
57
|
+
<p class="tw_text-base tw_text-secondary-dark dark:tw_text-secondary-light">
|
|
58
|
+
__COMPONENT_NAME__ callback — replace this with your implementation.
|
|
59
|
+
</p>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<!--
|
|
63
|
+
Scoped styles for this callback.
|
|
64
|
+
These styles only apply to this component — they won't leak to the rest of the widget.
|
|
65
|
+
You can also use Tailwind utility classes (prefixed with `tw_`) in the markup above.
|
|
66
|
+
-->
|
|
67
|
+
<style>
|
|
68
|
+
.__COMPONENT_SLUG__ {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: 0.5rem;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { format__COMPONENT_NAME__Label } from './__COMPONENT_SLUG__.utilities';
|
|
4
|
+
|
|
5
|
+
describe('__COMPONENT_NAME__ utilities', () => {
|
|
6
|
+
it('trims whitespace from label', () => {
|
|
7
|
+
expect(format__COMPONENT_NAME__Label(' hello ')).toBe('hello');
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for the __COMPONENT_NAME__ callback.
|
|
3
|
+
*
|
|
4
|
+
* Keep callback-specific helpers here — data formatting, validation, API calls, etc.
|
|
5
|
+
* This file is unit-tested independently of the Svelte component.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Example utility — replace with your own helpers.
|
|
10
|
+
*/
|
|
11
|
+
export function format__COMPONENT_NAME__Label(value: string): string {
|
|
12
|
+
return value.trim();
|
|
13
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
Type: stage
|
|
4
|
+
Name: __COMPONENT_NAME__
|
|
5
|
+
|
|
6
|
+
Custom stage component. Replace this description with your own.
|
|
7
|
+
|
|
8
|
+
A stage controls the layout and submission behaviour of an entire authentication
|
|
9
|
+
step (page node). It receives the full FRStep, maps each callback to its
|
|
10
|
+
component via CallbackMapper, and renders the form chrome (header, alerts,
|
|
11
|
+
submit button, links).
|
|
12
|
+
-->
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import type { FRStep } from '@forgerock/javascript-sdk';
|
|
16
|
+
import { afterUpdate, onDestroy, onMount } from 'svelte';
|
|
17
|
+
import { get } from 'svelte/store';
|
|
18
|
+
import type { z } from 'zod';
|
|
19
|
+
|
|
20
|
+
import { interpolate } from '$core/_utilities/i18n.utilities';
|
|
21
|
+
import T from '$components/_utilities/locale-strings.svelte';
|
|
22
|
+
import Alert from '$components/primitives/alert/alert.svelte';
|
|
23
|
+
import Button from '$components/primitives/button/button.svelte';
|
|
24
|
+
import Form from '$components/primitives/form/form.svelte';
|
|
25
|
+
import { convertStringToKey } from '$journey/stages/_utilities/step.utilities';
|
|
26
|
+
import { captureLinks } from '$journey/stages/_utilities/stage.utilities';
|
|
27
|
+
import { styleStore } from '$core/style.store';
|
|
28
|
+
import type { styleSchema } from '$core/style.store';
|
|
29
|
+
import CallbackMapper from '$journey/_utilities/callback-mapper.svelte';
|
|
30
|
+
|
|
31
|
+
import type {
|
|
32
|
+
CallbackMetadata,
|
|
33
|
+
StageFormObject,
|
|
34
|
+
StageJourneyObject,
|
|
35
|
+
StepMetadata,
|
|
36
|
+
} from '$journey/journey.interfaces';
|
|
37
|
+
import type { Maybe } from '$core/interfaces';
|
|
38
|
+
|
|
39
|
+
/** Display mode — determines which chrome is visible (header, links, etc.). */
|
|
40
|
+
export let componentStyle: 'app' | 'inline' | 'modal';
|
|
41
|
+
|
|
42
|
+
/** Form helpers — `form.submit()` triggers the journey's next step. */
|
|
43
|
+
export let form: StageFormObject;
|
|
44
|
+
|
|
45
|
+
/** Bound to the underlying <form> element for programmatic access. */
|
|
46
|
+
export let formEl: HTMLFormElement | null = null;
|
|
47
|
+
|
|
48
|
+
/** Journey-level state — includes `loading` flag and navigation helpers. */
|
|
49
|
+
export let journey: StageJourneyObject;
|
|
50
|
+
|
|
51
|
+
/** Step + callback metadata from AM — policies, derived helpers, stage header. */
|
|
52
|
+
export let metadata: Maybe<{ callbacks: CallbackMetadata[]; step: StepMetadata }>;
|
|
53
|
+
|
|
54
|
+
/** The raw FRStep from the JavaScript SDK — contains all callbacks for this step. */
|
|
55
|
+
export let step: FRStep;
|
|
56
|
+
|
|
57
|
+
// Subscribe to style store so the template can pass styles to child callbacks.
|
|
58
|
+
let currentStyle: z.infer<typeof styleSchema> = get(styleStore);
|
|
59
|
+
const unsubStyle = styleStore.subscribe((v) => (currentStyle = v));
|
|
60
|
+
onDestroy(unsubStyle);
|
|
61
|
+
|
|
62
|
+
let alertNeedsFocus = false;
|
|
63
|
+
let formMessageKey = '';
|
|
64
|
+
let linkWrapper: HTMLElement;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Auto-submits the form when the step declares itself self-submittable
|
|
68
|
+
* (e.g. a DeviceProfile or PollingWait callback that needs no user input).
|
|
69
|
+
*/
|
|
70
|
+
function determineSubmission() {
|
|
71
|
+
if (metadata?.step?.derived.isStepSelfSubmittable()) {
|
|
72
|
+
form?.submit();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
afterUpdate(() => {
|
|
77
|
+
alertNeedsFocus = !!form?.message;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
onMount(() => {
|
|
81
|
+
// In modal mode, intercept anchor clicks to navigate within the journey
|
|
82
|
+
// instead of performing a full page navigation.
|
|
83
|
+
if (componentStyle === 'modal') {
|
|
84
|
+
captureLinks(linkWrapper, journey);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
$: {
|
|
89
|
+
formMessageKey = convertStringToKey(form?.message);
|
|
90
|
+
}
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<!--
|
|
94
|
+
Replace or extend the markup below to customise the stage layout.
|
|
95
|
+
The key pieces to keep:
|
|
96
|
+
1. <Form> wrapper with `onSubmitWhenValid` bound to `form.submit`
|
|
97
|
+
2. The {#each} block that maps callbacks via <CallbackMapper>
|
|
98
|
+
3. A submit <Button> (unless the step is fully self-submittable)
|
|
99
|
+
-->
|
|
100
|
+
<Form bind:formEl ariaDescribedBy="__COMPONENT_SLUG__FailureAlert" onSubmitWhenValid={form?.submit}>
|
|
101
|
+
{#if componentStyle !== 'inline'}
|
|
102
|
+
<h1 class="tw_primary-header dark:tw_primary-header_dark">
|
|
103
|
+
<T key="loginHeader" />
|
|
104
|
+
</h1>
|
|
105
|
+
{/if}
|
|
106
|
+
|
|
107
|
+
{#if form?.message}
|
|
108
|
+
<Alert id="__COMPONENT_SLUG__FailureAlert" needsFocus={alertNeedsFocus} type="error">
|
|
109
|
+
{interpolate(formMessageKey, null, form?.message)}
|
|
110
|
+
</Alert>
|
|
111
|
+
{/if}
|
|
112
|
+
|
|
113
|
+
{#each step?.callbacks as callback, idx}
|
|
114
|
+
<CallbackMapper
|
|
115
|
+
props={{
|
|
116
|
+
callback,
|
|
117
|
+
callbackMetadata: metadata?.callbacks[idx],
|
|
118
|
+
selfSubmitFunction: determineSubmission,
|
|
119
|
+
stepMetadata: metadata?.step && { ...metadata.step },
|
|
120
|
+
style: currentStyle,
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
{/each}
|
|
124
|
+
|
|
125
|
+
{#if metadata?.step?.derived.isUserInputOptional || !metadata?.step?.derived.isStepSelfSubmittable()}
|
|
126
|
+
<Button busy={journey?.loading} style="primary" type="submit" width="full">
|
|
127
|
+
<T key="loginButton" />
|
|
128
|
+
</Button>
|
|
129
|
+
{/if}
|
|
130
|
+
|
|
131
|
+
{#if componentStyle !== 'inline'}
|
|
132
|
+
<p
|
|
133
|
+
bind:this={linkWrapper}
|
|
134
|
+
class="tw_text-base tw_text-center tw_py-4 tw_text-secondary-dark dark:tw_text-secondary-light"
|
|
135
|
+
>
|
|
136
|
+
<T key="dontHaveAnAccount" html={true} />
|
|
137
|
+
</p>
|
|
138
|
+
{/if}
|
|
139
|
+
</Form>
|
|
140
|
+
|
|
141
|
+
<!--
|
|
142
|
+
Scoped styles for this stage.
|
|
143
|
+
These styles only apply to this component — they won't leak to the rest of the widget.
|
|
144
|
+
You can also use Tailwind utility classes (prefixed with `tw_`) in the markup above.
|
|
145
|
+
-->
|
|
146
|
+
<style>
|
|
147
|
+
/* Add your custom stage styles here. */
|
|
148
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { format__COMPONENT_NAME__Label } from './__COMPONENT_SLUG__.utilities';
|
|
4
|
+
|
|
5
|
+
describe('__COMPONENT_NAME__ utilities', () => {
|
|
6
|
+
it('trims whitespace from label', () => {
|
|
7
|
+
expect(format__COMPONENT_NAME__Label(' hello ')).toBe('hello');
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for the __COMPONENT_NAME__ stage.
|
|
3
|
+
*
|
|
4
|
+
* Keep stage-specific helpers here — data formatting, validation, API calls, etc.
|
|
5
|
+
* This file is unit-tested independently of the Svelte component.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Example utility — replace with your own helpers.
|
|
10
|
+
*/
|
|
11
|
+
export function format__COMPONENT_NAME__Label(value: string): string {
|
|
12
|
+
return value.trim();
|
|
13
|
+
}
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgerock/login-framework-cli",
|
|
3
|
+
"version": "0.0.0-beta.0",
|
|
4
|
+
"description": "CLI tool for scaffolding and managing Ping Login Widget and Login App custom component projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": "./dist/main.js",
|
|
7
|
+
"main": "./dist/main.js",
|
|
8
|
+
"module": "./dist/main.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"ping-lf": "./dist/main.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"scripts"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ping-identity",
|
|
18
|
+
"forgerock",
|
|
19
|
+
"login",
|
|
20
|
+
"widget",
|
|
21
|
+
"cli",
|
|
22
|
+
"generator",
|
|
23
|
+
"svelte"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/ForgeRock/forgerock-web-login-framework.git",
|
|
29
|
+
"directory": "tools/cli"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20.0.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@effect/cli": "^0.75.0",
|
|
39
|
+
"@effect/platform": "^0.96.0",
|
|
40
|
+
"@effect/platform-node": "^0.106.0",
|
|
41
|
+
"@effect/printer": "^0.49.0",
|
|
42
|
+
"@effect/printer-ansi": "^0.49.0",
|
|
43
|
+
"@effect/typeclass": "^0.40.0",
|
|
44
|
+
"effect": "^3.21.0",
|
|
45
|
+
"tar": "^7.5.13"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"typescript": "^5.2.2",
|
|
49
|
+
"vitest": "^3.0.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "rm -rf dist && tsc && chmod +x dist/main.js && ([ -d templates ] && cp -r templates/ dist/templates/ || true)",
|
|
53
|
+
"dev": "tsc --watch",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"test:watch": "vitest"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Thin Effect runner for generating the custom component registry.
|
|
4
|
+
*
|
|
5
|
+
* Called by:
|
|
6
|
+
* - packages/login-widget/package.json "prebuild"
|
|
7
|
+
* - Root package.json "generate:registry"
|
|
8
|
+
*
|
|
9
|
+
* Requires the CLI to be compiled first:
|
|
10
|
+
* pnpm --filter @ping-identity/login-framework-cli run build
|
|
11
|
+
*/
|
|
12
|
+
import { Effect } from 'effect';
|
|
13
|
+
import { NodeContext, NodeRuntime } from '@effect/platform-node';
|
|
14
|
+
|
|
15
|
+
const { runRegistryScript } = await import('../dist/services/registry.js');
|
|
16
|
+
|
|
17
|
+
const projectDir = process.argv[2];
|
|
18
|
+
if (!projectDir) {
|
|
19
|
+
console.error('Usage: node generate-registry.mjs <projectDir>');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
NodeRuntime.runMain(runRegistryScript(projectDir).pipe(Effect.provide(NodeContext.layer)));
|