@ofidj/generator-fidj 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +93 -58
  2. package/bin/create-fidj.cjs +54 -0
  3. package/generators/app/index.js +58 -189
  4. package/generators/app/templates/typescript/README.md +73 -0
  5. package/generators/app/templates/typescript/app.config.json +10 -0
  6. package/generators/app/templates/typescript/gitignore +5 -0
  7. package/generators/app/templates/typescript/package.json +25 -0
  8. package/generators/app/templates/typescript/public/fidj-logo.png +0 -0
  9. package/generators/app/templates/typescript/public/index.html +16 -0
  10. package/generators/app/templates/typescript/scripts/build.mjs +46 -0
  11. package/generators/app/templates/typescript/scripts/privacy-check.mjs +21 -0
  12. package/generators/app/templates/typescript/scripts/render-content.mjs +14 -0
  13. package/generators/app/templates/typescript/server/data-store.ts +123 -0
  14. package/generators/app/templates/typescript/server/index.ts +329 -0
  15. package/generators/app/templates/typescript/server/privacy-adapter.ts +21 -0
  16. package/generators/app/templates/typescript/src/content.ts +416 -0
  17. package/generators/app/templates/typescript/src/main.ts +243 -0
  18. package/generators/app/templates/typescript/src/style.css +639 -0
  19. package/generators/app/templates/typescript/test/server.test.mjs +287 -0
  20. package/generators/app/templates/typescript/tsconfig.json +15 -0
  21. package/lib/app-module.cjs +59 -0
  22. package/lib/scaffold.cjs +145 -0
  23. package/package.json +18 -12
  24. package/generators/app/templates/app2018/.travis.yml +0 -35
  25. package/generators/app/templates/app2018/LICENSE +0 -21
  26. package/generators/app/templates/app2018/Procfile +0 -1
  27. package/generators/app/templates/app2018/README.md +0 -49
  28. package/generators/app/templates/app2018/config.xml +0 -91
  29. package/generators/app/templates/app2018/gulpfile.js +0 -63
  30. package/generators/app/templates/app2018/ionic.config.json +0 -9
  31. package/generators/app/templates/app2018/package.json +0 -90
  32. package/generators/app/templates/app2018/platforms/README.md +0 -1
  33. package/generators/app/templates/app2018/resources/README.md +0 -6
  34. package/generators/app/templates/app2018/resources/icon.png +0 -0
  35. package/generators/app/templates/app2018/resources/marketing-01-ipad.png +0 -0
  36. package/generators/app/templates/app2018/resources/marketing-01-iphone.png +0 -0
  37. package/generators/app/templates/app2018/resources/marketing-02-ipad.png +0 -0
  38. package/generators/app/templates/app2018/resources/marketing-02-iphone.png +0 -0
  39. package/generators/app/templates/app2018/resources/marketing-03-ipad.png +0 -0
  40. package/generators/app/templates/app2018/resources/marketing-03-iphone.png +0 -0
  41. package/generators/app/templates/app2018/resources/marketing.json +0 -19
  42. package/generators/app/templates/app2018/resources/splash.png +0 -0
  43. package/generators/app/templates/app2018/src/app/app.component.ts +0 -88
  44. package/generators/app/templates/app2018/src/app/app.html +0 -19
  45. package/generators/app/templates/app2018/src/app/app.module.ts +0 -40
  46. package/generators/app/templates/app2018/src/app/app.scss +0 -16
  47. package/generators/app/templates/app2018/src/app/main.ts +0 -5
  48. package/generators/app/templates/app2018/src/app/shared/card.model.ts +0 -10
  49. package/generators/app/templates/app2018/src/app/shared/profile.service.ts +0 -46
  50. package/generators/app/templates/app2018/src/app/shared/shared.module.ts +0 -35
  51. package/generators/app/templates/app2018/src/app/shared/storage.service.ts +0 -11
  52. package/generators/app/templates/app2018/src/app/shared/version.const.ts +0 -5
  53. package/generators/app/templates/app2018/src/assets/icon/favicon.ico +0 -0
  54. package/generators/app/templates/app2018/src/assets/imgs/gg.png +0 -0
  55. package/generators/app/templates/app2018/src/assets/imgs/github.png +0 -0
  56. package/generators/app/templates/app2018/src/assets/imgs/login.svg +0 -5668
  57. package/generators/app/templates/app2018/src/assets/imgs/logo.png +0 -0
  58. package/generators/app/templates/app2018/src/index.html +0 -49
  59. package/generators/app/templates/app2018/src/manifest.json +0 -13
  60. package/generators/app/templates/app2018/src/pages/home/home.html +0 -56
  61. package/generators/app/templates/app2018/src/pages/home/home.scss +0 -3
  62. package/generators/app/templates/app2018/src/pages/home/home.ts +0 -126
  63. package/generators/app/templates/app2018/src/pages/login/login.html +0 -56
  64. package/generators/app/templates/app2018/src/pages/login/login.scss +0 -44
  65. package/generators/app/templates/app2018/src/pages/login/login.ts +0 -59
  66. package/generators/app/templates/app2018/src/pages/profile/profile.html +0 -33
  67. package/generators/app/templates/app2018/src/pages/profile/profile.scss +0 -3
  68. package/generators/app/templates/app2018/src/pages/profile/profile.ts +0 -36
  69. package/generators/app/templates/app2018/src/service-worker.js +0 -31
  70. package/generators/app/templates/app2018/src/theme/variables.scss +0 -88
  71. package/generators/app/templates/app2018/tests/karma.unit-tests.conf.js +0 -84
  72. package/generators/app/templates/app2018/tests/unit/app.test.js +0 -10
  73. package/generators/app/templates/app2018/tsconfig.json +0 -28
  74. package/generators/app/templates/app2018/tslint.json +0 -8
  75. package/generators/app/templates/app2018/web.js +0 -21
  76. package/generators/app/templates/app2021/.travis.yml +0 -32
  77. package/generators/app/templates/app2021/LICENSE +0 -21
  78. package/generators/app/templates/app2021/Procfile +0 -1
  79. package/generators/app/templates/app2021/README.md +0 -45
  80. package/generators/app/templates/app2021/angular.json +0 -188
  81. package/generators/app/templates/app2021/browserslist +0 -12
  82. package/generators/app/templates/app2021/ionic.config.json +0 -9
  83. package/generators/app/templates/app2021/karma.conf.js +0 -31
  84. package/generators/app/templates/app2021/package-lock.json +0 -5
  85. package/generators/app/templates/app2021/package.json +0 -77
  86. package/generators/app/templates/app2021/platforms/README.md +0 -1
  87. package/generators/app/templates/app2021/resources/README.md +0 -6
  88. package/generators/app/templates/app2021/resources/icon.png +0 -0
  89. package/generators/app/templates/app2021/resources/marketing-01-ipad.png +0 -0
  90. package/generators/app/templates/app2021/resources/marketing-01-iphone.png +0 -0
  91. package/generators/app/templates/app2021/resources/marketing-02-ipad.png +0 -0
  92. package/generators/app/templates/app2021/resources/marketing-02-iphone.png +0 -0
  93. package/generators/app/templates/app2021/resources/marketing-03-ipad.png +0 -0
  94. package/generators/app/templates/app2021/resources/marketing-03-iphone.png +0 -0
  95. package/generators/app/templates/app2021/resources/marketing.json +0 -19
  96. package/generators/app/templates/app2021/resources/splash.png +0 -0
  97. package/generators/app/templates/app2021/src/app/app-routing.module.ts +0 -25
  98. package/generators/app/templates/app2021/src/app/app.component.html +0 -3
  99. package/generators/app/templates/app2021/src/app/app.component.scss +0 -0
  100. package/generators/app/templates/app2021/src/app/app.component.spec.ts +0 -50
  101. package/generators/app/templates/app2021/src/app/app.component.ts +0 -28
  102. package/generators/app/templates/app2021/src/app/app.module.ts +0 -24
  103. package/generators/app/templates/app2021/src/app/content/content-routing.module.ts +0 -16
  104. package/generators/app/templates/app2021/src/app/content/content.module.ts +0 -20
  105. package/generators/app/templates/app2021/src/app/content/content.page.html +0 -31
  106. package/generators/app/templates/app2021/src/app/content/content.page.scss +0 -0
  107. package/generators/app/templates/app2021/src/app/content/content.page.ts +0 -26
  108. package/generators/app/templates/app2021/src/app/explore-container/explore-container.component.html +0 -4
  109. package/generators/app/templates/app2021/src/app/explore-container/explore-container.component.scss +0 -4
  110. package/generators/app/templates/app2021/src/app/explore-container/explore-container.component.spec.ts +0 -24
  111. package/generators/app/templates/app2021/src/app/explore-container/explore-container.component.ts +0 -16
  112. package/generators/app/templates/app2021/src/app/explore-container/explore-container.module.ts +0 -14
  113. package/generators/app/templates/app2021/src/app/my/my-routing.module.ts +0 -36
  114. package/generators/app/templates/app2021/src/app/my/my.module.ts +0 -19
  115. package/generators/app/templates/app2021/src/app/my/my.page.html +0 -15
  116. package/generators/app/templates/app2021/src/app/my/my.page.scss +0 -1
  117. package/generators/app/templates/app2021/src/app/my/my.page.spec.ts +0 -26
  118. package/generators/app/templates/app2021/src/app/my/my.page.ts +0 -25
  119. package/generators/app/templates/app2021/src/app/profile/profile-routing.module.ts +0 -16
  120. package/generators/app/templates/app2021/src/app/profile/profile.module.ts +0 -20
  121. package/generators/app/templates/app2021/src/app/profile/profile.page.html +0 -49
  122. package/generators/app/templates/app2021/src/app/profile/profile.page.scss +0 -0
  123. package/generators/app/templates/app2021/src/app/profile/profile.page.spec.ts +0 -25
  124. package/generators/app/templates/app2021/src/app/profile/profile.page.ts +0 -44
  125. package/generators/app/templates/app2021/src/app/shared/const.ts +0 -3
  126. package/generators/app/templates/app2021/src/app/signin/signin-routing.module.ts +0 -16
  127. package/generators/app/templates/app2021/src/app/signin/signin.module.ts +0 -18
  128. package/generators/app/templates/app2021/src/app/signin/signin.page.html +0 -53
  129. package/generators/app/templates/app2021/src/app/signin/signin.page.scss +0 -36
  130. package/generators/app/templates/app2021/src/app/signin/signin.page.ts +0 -69
  131. package/generators/app/templates/app2021/src/assets/icon/favicon.png +0 -0
  132. package/generators/app/templates/app2021/src/assets/shapes.svg +0 -1
  133. package/generators/app/templates/app2021/src/environments/environment.prod.ts +0 -3
  134. package/generators/app/templates/app2021/src/environments/environment.ts +0 -16
  135. package/generators/app/templates/app2021/src/global.scss +0 -26
  136. package/generators/app/templates/app2021/src/index.html +0 -26
  137. package/generators/app/templates/app2021/src/main.ts +0 -12
  138. package/generators/app/templates/app2021/src/polyfills.ts +0 -67
  139. package/generators/app/templates/app2021/src/test.ts +0 -20
  140. package/generators/app/templates/app2021/src/theme/variables.scss +0 -232
  141. package/generators/app/templates/app2021/src/zone-flags.ts +0 -5
  142. package/generators/app/templates/app2021/tests/protractor.conf.js +0 -36
  143. package/generators/app/templates/app2021/tests/src/app.e2e-spec.ts +0 -14
  144. package/generators/app/templates/app2021/tests/src/app.po.ts +0 -11
  145. package/generators/app/templates/app2021/tests/tsconfig.json +0 -13
  146. package/generators/app/templates/app2021/tsconfig.app.json +0 -18
  147. package/generators/app/templates/app2021/tsconfig.json +0 -23
  148. package/generators/app/templates/app2021/tsconfig.spec.json +0 -18
  149. package/generators/app/templates/app2021/tslint.json +0 -149
  150. package/generators/app/templates/app2021/web.js +0 -21
package/README.md CHANGED
@@ -1,74 +1,109 @@
1
1
  # @ofidj/generator-fidj
2
2
 
3
- [![NPM version][npm-image]][npm-url]
4
- [![Build Status][travis-image]][travis-url]
3
+ Generate a Fidj-integrated TypeScript app with a short command. Public identity and content are generator inputs; authentication and per-app privacy are reusable template behavior. Node 22 or 24 is the validation matrix.
5
4
 
6
- > build great mobile and web angular/ionic apps based on fidj.ovh authentication.
7
- >
8
- > _Renamed from `generator-fidj` at 1.0.0. The old `generator-fidj@3.x` is deprecated. The yeoman command becomes `yo @ofidj/fidj` (note the `@ofidj/` prefix)._
5
+ ## Content app static hosting
9
6
 
10
- ## Prerequisites
7
+ ```sh
8
+ create-fidj my-app --app-id YOUR_FIDJ_ID --title "My App" --welcome "Welcome" --content "<p>About my app</p>" --domain example.com
9
+ cd my-app
10
+ npm install && npm run build-prod
11
+ ```
11
12
 
12
- Look at mat's gist : https://gist.github.com/mlefree/2156f66dfb441f107bef157dde56a836
13
+ Serve `www/` on a static host. It contains your public content, SDK sign-in/account creation, current roles, consent/history, scoped export and confirmed departure, plus `CNAME`. Private signing keys are never needed in the browser. `npm start` supplies an optional Node preview; this mode makes its API calls directly to Fidj.
13
14
 
14
- ## Installation
15
+ `--content` is trusted developer-authored HTML (like any checked-in application source), never untrusted visitor input. Set real terms before release; the generated agreement is explicitly a demo. The content app has no independent user database. Erasure/export cover Fidj-held membership records, and pending cleanup stays pending.
15
16
 
16
- First, install [Yeoman](http://yeoman.io) and generator-fidj using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)) :
17
- ```bash
18
- npm install -g yo
19
- npm install -g @ionic/cli
20
- npm install -g @angular/cli
21
- npm install -g @ofidj/generator-fidj
22
- ```
23
- Then generate your new project:
24
- ```bash
25
- yo @ofidj/fidj
26
- ```
27
- or as an expert :
28
- ```bash
29
- yo @ofidj/fidj my-app app2021 your-app-id "" me-as-user "my description" \
30
- "Welcome there" \
31
- "Hey<br>Heres my content: <img src=blank /><br> \o/ "
32
- ```
17
+ ## Backend example protected actions
33
18
 
34
- ## Development
19
+ Omit `--content` to generate Studio Notes: a browser client plus Node backend with private persisted notes. The backend revalidates the session and live app roles for every protected request. Owner/Editor may write; other members may read their own notes. This mode requires Node hosting and is separate from the static content app scenario.
35
20
 
36
- Make sure you've got yeoman installed :
37
- ```bash
38
- npm install -g yo
39
- npm install -g @ionic/cli
40
- npm install -g @angular/cli
41
- ```
21
+ Configure the generated privacy adapter so departure from either Studio Notes or Fidj erases the same app data. Notes persist outside disposable output. Failed cleanup stays pending in Fidj and can be retried; completed receipts remain visible. See the generated README for server-side configuration and persistence limits.
42
22
 
43
- Clone the repo, install it :
44
- ```bash
45
- cd generator-fidj
46
- npm install
47
- npm link
48
- ```
23
+ ## CLI and local development
24
+
25
+ The package exposes `create-fidj`; from its checkout use `node bin/create-fidj.cjs`. Yeoman `yo @ofidj/fidj my-app --app-id YOUR_FIDJ_ID` invokes the same scaffolder and accepts the content/title/welcome/domain options. The old `app2021` positional command is a historical reference, not the maintained interface.
26
+
27
+ - `--anonymous true|false`: show or hide anonymous entry in content apps (default: `true`). Set `--anonymous false` for a sign-in-only entry flow, as mleweb does.
28
+ - `--api-endpoint`: select the API (default: hosted sandbox).
29
+ - `--sdk-path` or `FIDJ_SDK_DIR`: use a built local SDK during coordinated development.
30
+ - `--local` or `FIDJ_LOCAL=true`: use the loopback API/console. Test credentials stay in the validation guide, outside the content app UI. Supply the matching local app ID; `FIDJ_APP_ID` can override it.
31
+ - `--replace`: regenerate only a destination containing `.fidj-generated`; unmarked projects are protected.
32
+
33
+ Generation writes `.env.example`, `.env` and public `app.config.json`. Static configuration is embedded at build time: regenerate/rebuild when changing endpoints. Notes server configuration is read at runtime. Do not place secrets in any public configuration or content input.
34
+
35
+ During this unreleased milestone, build `../fidj-node` and pass `--sdk-path ../fidj-node/dist`. Committed templates use registry dependency `@ofidj/node ^3.6.24`; a registry-only install is not validated until coordinated versions are published.
36
+
37
+ ## Real validation repository
38
+
39
+ [mleweb](https://github.com/mlefree/mleweb) is the thin command-line validation fixture whose generated website is mlefree.com. Its `package.json` passes the original Mario GIF, welcome text and About/CV/contact links directly into this generator. No custom downstream renderer is required. GitHub CI runs the same generation/build path on Node 22/24 and uploads artifacts. Publishing the site to gh-pages, which is what mlefree.com serves, is a separate deliberate job: it runs on mleweb's `master` or on an explicit workflow dispatch, never from a version branch.
40
+
41
+ Run `npm test` for scaffolding/CLI safety tests. Generated projects include TypeScript checking and HTTP integration tests for live authorization and privacy isolation. Local acceptance steps are in the workspace's `product-plan/09-generated-app-validation.md`.
42
+
43
+
44
+ ## Releasing to npm
45
+
46
+ Pushing to the `package` branch publishes the package, the same convention the
47
+ SDK and contracts repositories use. CI installs, runs the tests and publishes
48
+ with `NPM_TOKEN`; this package publishes from the repository root rather than
49
+ from a `dist` directory, because it ships its sources.
50
+
51
+ The package contains `bin/`, `lib/` and the `typescript` template only. The
52
+ `app2018` and `app2021` Yeoman templates are excluded: nothing reads them, and
53
+ they accounted for 11.8MB of the 11.9MB published. `main` points at
54
+ `lib/scaffold.cjs`, so `require('@ofidj/generator-fidj')` returns `{ scaffold }`
55
+ alongside the `create-fidj` binary.
56
+
57
+ Publish contracts before the SDK, and the SDK before anything that resolves it
58
+ from the registry: the SDK depends on `@ofidj/contracts` by range, so a build
59
+ picks up whatever is published at the time.
60
+
61
+ ## Entry flow
49
62
 
50
- And then use your local Fidj generator :
51
- ```bash
52
- mkdir your-app && cd your-app && \
53
- yo @ofidj/fidj my-app app2021 your-app-id "" me-as-user "my description" \
54
- "Welcome there" \
55
- "Hey<br>Heres my content: <img src=blank /><br> \o/ "
63
+ The generated content app opens on `/#/signin`. Sign in, or choose **Enter anonymously** when enabled, to open `/#/content`, containing the supplied HTML. Signed-in users can open **My privacy** separately. Sign-out and departure return to the sign-in screen. Anonymous content is public; this navigation flow is not a security boundary for static assets.
56
64
 
57
- # look at the code : code .
58
- # or start it : npm start
65
+ ## Compose an existing app as a module
66
+
67
+ Build your application for the `/module/` base URL, then pass its public output to the same generator:
68
+
69
+ ```sh
70
+ create-fidj my-app --app-id YOUR_FIDJ_ID --title "My App" --welcome "Welcome back" --description "Your app description" --anonymous false --module ./built-console --module-entry 'index.html#/my'
71
+ cd my-app && npm install && npm run build-prod
59
72
  ```
60
73
 
61
- ## License
74
+ The result is one static website: the generated SDK sign-in entry and the module under `www/module/`. After login, the entry opens the module on the same origin. The module must use the same public app ID/API and independently validate authorization for its own operations. The generator copies public build assets without changing their source; module input cannot contain environment files, dependency directories or symlinks.
75
+
76
+ Hash routes other than the generated entry/content/privacy views are forwarded to the module, preserving existing public cards and console links. The module remains responsible for guarding private routes.
77
+
78
+ The module entry receives a `meta[name="fidj-signin"]` URL, relative to its base URL. A module can send its sign-in, logout or expired-session flow there. Fidj's console implements this handoff and preserves departure status. The generated preview serves module assets from an explicit build manifest, including directory index URLs.
79
+
80
+ `fidj-app` now exercises this path with `npm run create:local`: its owner/profile/privacy features remain an explicit Angular console module, while the generator owns the shared entry and final assembly. The local launcher serves the generated Fidj output on port 4200. The source console is maintained outside disposable `.gen` and must be rebuilt before regenerating.
81
+
82
+ ## Generated account lifecycle
83
+
84
+ Content and module entries include `#/forgot`, `#/reset`, `#/verify`, and authenticated `#/account` screens in the same split layout as sign-in. These routes remain in the generated shell when an application module is attached. Forgot-password responses are neutral; verification requires an explicit click. `My account` provides verification status and resend. Password reset affects the shared Fidj identity across apps. Configure the API’s trusted account UI URL for email links; the current generated API integration requires the coordinated 3.6.24 SDK/API. The server-backed Notes template remains a separate integration example.
85
+
86
+ ## App data adapter
87
+
88
+ The Notes server exposes `POST /fidj/privacy` for HMAC-authenticated, timestamped export/erase operations. Set a private `FIDJ_PRIVACY_ADAPTER_KEY` and register the same app ID, endpoint and key in the API’s server-side `FIDJ_PRIVACY_ADAPTERS`. Static content apps need no independent data adapter. `FIDJ_DATA_DIR` must stay outside `www`, `dist` and disposable generated output; the generated environment defaults to a sibling data directory.
89
+
90
+ The file adapter uses atomic writes and a serialized queue for one writer process. Replace it with a transactional database for multi-instance hosting. Erasure receipts retain a hashed subject for replay protection, pruned after 30 days on the next write. Backups and unregistered stores are not covered. Tests exercise live authorization, restart persistence, private exports, adapter authentication, failed cleanup and duplicate-request safety.
91
+
92
+
93
+ ### Check a registered data handler
94
+
95
+ Generated starters include `npm run privacy:check`: configure the server-only `FIDJ_PRIVACY_ADAPTER_KEY` in `.env`, start the app, then run the command. It signs a readiness request, verifies capabilities and probes durable storage without exporting or deleting user records. `FIDJ_APP_URL` can override the default loopback URL. `npm run privacy:rehearse` builds and exercises an isolated temporary data store, including scoped export, failure, retry and persistence. Production app data and credentials are never inputs to that rehearsal.
96
+
97
+ Readiness confirms this handler only. Register its trusted URL and independent secret with the Fidj API operator; the app owner console can then check the same connection. Group roles granted in Fidj are enforced by the generated backend on each protected operation.
98
+
99
+ ## Generate an OIDC app
100
+
101
+ `--oidc-issuer` switches the shared content/module entry to “Continue with Fidj”. The issuer owns password entry; the generator preserves your title, welcome message, logo/content inputs and anonymous-entry choice.
102
+
103
+ ```sh
104
+ create-fidj my-app --app-id YOUR_APP_ID --api-endpoint https://api.sandbox.fidj.ovh/v3 --oidc-issuer https://api.sandbox.fidj.ovh/oidc --anonymous false --content '<h1>My app</h1>'
105
+ ```
62
106
 
63
- MIT 2021 © [fidj.ovh](fidj.ovh)
107
+ An operator must enable that issuer before this command can authenticate. Register the exact deployed entry URL as the callback; it must not contain a fragment. Local loopback HTTP is supported. During the unreleased beta, use the coordinated SDK checkout through `--sdk-path`; registry-only publication is still pending.
64
108
 
65
- [npm-image]: https://badge.fury.io/js/@ofidj%2Fgenerator-fidj.svg
66
- [npm-url]: https://npmjs.org/package/@ofidj/generator-fidj
67
- [travis-image]: https://travis-ci.org/ofidj/generator-fidj.svg?branch=master
68
- [travis-url]: https://travis-ci.org/ofidj/generator-fidj
69
- [daviddm-image]: https://david-dm.org/ofidj/generator-fidj.svg?theme=shields.io
70
- [daviddm-url]: https://david-dm.org/ofidj/generator-fidj
71
- [coveralls-image]: https://coveralls.io/repos/ofidj/generator-fidj/badge.svg
72
- [coveralls-url]: https://coveralls.io/r/ofidj/generator-fidj
73
- [codecov-image]: https://codecov.io/gh/ofidj/generator-fidj/branch/master/graph/badge.svg
74
- [codecov-url]: https://codecov.io/gh/ofidj/generator-fidj
109
+ OIDC currently supports static content and application-module assemblies. The Notes storage fixture retains its existing auth flow; no migration of stored Notes subjects is implied. Static HTML/assets remain public regardless of the login screen. Confidential data needs server authorization, preferably with an HttpOnly backend session. mleweb remains the command-line generator fixture: retain the original Mario and About/CV content, and activate OIDC only after its target issuer and callback are configured.
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ const { parseArgs } = require("node:util");
3
+ const { scaffold } = require("../lib/scaffold.cjs");
4
+ try {
5
+ const { values, positionals } = parseArgs({
6
+ allowPositionals: true,
7
+ options: {
8
+ "app-id": { type: "string" },
9
+ "api-endpoint": { type: "string" },
10
+ "oidc-issuer": { type: "string" },
11
+ "sdk-path": { type: "string" },
12
+ title: { type: "string" },
13
+ welcome: { type: "string" },
14
+ description: { type: "string" },
15
+ content: { type: "string" },
16
+ anonymous: { type: "string" },
17
+ domain: { type: "string" },
18
+ module: { type: "string" },
19
+ "module-entry": { type: "string" },
20
+ local: { type: "boolean" },
21
+ replace: { type: "boolean" },
22
+ help: { type: "boolean" },
23
+ },
24
+ });
25
+ if (values.help || positionals.length !== 1) {
26
+ console.log(
27
+ "Usage: create-fidj <directory> --app-id <fidjId> [--api-endpoint <url>] [--title <text> --welcome <text> --description <text> --content <html> --domain <hostname>] [--module <built-directory> --module-entry <index.html#/route>] [--oidc-issuer https://api.example/oidc] [--anonymous true|false] [--local] [--replace]",
28
+ );
29
+ process.exitCode = values.help ? 0 : 1;
30
+ } else {
31
+ const dir = scaffold(positionals[0], {
32
+ appId: process.env.FIDJ_APP_ID || values["app-id"],
33
+ apiEndpoint: values["api-endpoint"],
34
+ oidcIssuer: values["oidc-issuer"],
35
+ sdkPath: values["sdk-path"] || process.env.FIDJ_SDK_DIR,
36
+ title: values.title,
37
+ welcome: values.welcome,
38
+ description: values.description,
39
+ content: values.content,
40
+ anonymous: values.anonymous,
41
+ domain: values.domain,
42
+ module: values.module,
43
+ moduleEntry: values["module-entry"],
44
+ local: values.local || process.env.FIDJ_LOCAL === "true",
45
+ replace: values.replace,
46
+ });
47
+ console.log(
48
+ `Created ${dir}\nNext: copy .env.example to .env, then npm install && npm run build && npm start.`,
49
+ );
50
+ }
51
+ } catch (error) {
52
+ console.error(error.message);
53
+ process.exitCode = 1;
54
+ }
@@ -1,200 +1,69 @@
1
- const Generator = require('yeoman-generator');
2
- const yosay = require('yosay');
3
- const chalk = require('chalk');
1
+ const Generator = require("yeoman-generator");
2
+ const { scaffold } = require("../../lib/scaffold.cjs");
4
3
 
5
4
  module.exports = class extends Generator {
6
5
  constructor(args, opts) {
7
6
  super(args, opts);
8
-
9
- this.hasBeenRecordedInFidjOvh = true;
10
- this.templateName = 'app2021'; //'app2021'; //'app2018' ''ionic2020'
11
-
12
- this.option('skip-welcome-message', {
13
- desc: 'Skips the welcome message',
14
- type: Boolean
7
+ this.argument("appname", { type: String, required: false });
8
+ this.option("app-id", { type: String });
9
+ for (const key of [
10
+ "title",
11
+ "welcome",
12
+ "description",
13
+ "content",
14
+ "domain",
15
+ "sdk-path",
16
+ "anonymous",
17
+ "module",
18
+ "module-entry",
19
+ ])
20
+ this.option(key, { type: String });
21
+ this.option("api-endpoint", {
22
+ type: String,
23
+ default: "https://api.sandbox.fidj.ovh/v3",
15
24
  });
16
-
17
- this.argument('appname', {type: String, required: false, desc: 'Your app name'});
18
- this.argument('appType', {type: String, required: false, desc: 'For ex: "app2021" '});
19
- this.argument('appId', {type: String, required: false});
20
- this.argument('appOptions', {type: String, required: false});
21
- this.argument('appUserName', {type: String, required: false});
22
- this.argument('appDescription', {type: String, required: false});
23
- this.argument('appWelcome', {type: String, required: false});
24
- this.argument('appContent', {type: String, required: false});
25
- }
26
-
27
- async initializing() {
28
- this.pkg = require('../../package.json');
29
25
  }
30
-
31
26
  async prompting() {
32
- if (!this.options['skip-welcome-message'] && !this.options.appId) {
33
- this.log(yosay('\'Allo \'Welcome to ' + chalk.red('fidj.ovh') + ' generator'));
34
-
35
- const promptConditions = [{
36
- type: 'confirm',
37
- name: 'hasBeenRecordedInFidjOvh',
38
- message: 'Did you recorded your app in fidj.ovh and received your appId ?',
39
- default: false
40
- }];
41
-
42
- const conditions = await this.prompt(promptConditions);
43
- this.hasBeenRecordedInFidjOvh = !!conditions.hasBeenRecordedInFidjOvh;
44
- if (!this.hasBeenRecordedInFidjOvh) {
45
- const err = 'You need to submit your app on https://fidj.ovh first. ' +
46
- 'It will help you to build a valid app name and give you a appId.';
47
- this.log(yosay('Sorry : ' + chalk.red(err) + ' See you in 2 minutes ?'));
48
- }
49
- }
50
-
51
- if (!this.options.appname || !this.options.appUserName || !this.options.appDescription) {
52
- const prompts = [
53
- {
54
- type: 'input',
55
- name: 'appUserName',
56
- message: 'Your (github) user name'
57
- },
58
- {
59
- type: 'input',
60
- name: 'appName',
61
- message: 'Your app name (as shown on device)',
62
- default: this.appname.replace(/[^\w\s]/gi, '').replace(/\s/g, '_').replace(/\s+/g, '').replace(/[\. ,:-]+/g, '').toLowerCase()
63
- },
64
- {
65
- type: 'input',
66
- name: 'appDescription',
67
- message: 'App description',
68
- default: this.appname
69
- }
70
- ];
71
-
72
- this.props = await this.prompt(prompts);
73
- } else {
74
- this.props = {
75
- appName: this.options.appname,
76
- appUserName: this.options.appUserName,
77
- appDescription: this.options.appDescription,
78
- appWelcome: this.options.appWelcome || '<h1>Welcome</h1>',
79
- appContent: this.options.appContent || '<h1>Hello</h1>'
80
- };
81
- }
82
-
83
- const pack = this.props.appUserName.replace(/[^\w\s]/gi, '').replace(/\s+/g, '').replace(/[\. ,:-]+/g, '').toLowerCase();
84
- const age = this.props.appName.replace(/[^\w\s]/gi, '').replace(/\s/g, '_').replace(/\s+/g, '').replace(/[\. ,:-]+/g, '').toLowerCase();
85
- const packageDefault = 'ovh.' + (pack ? pack : 'fidj') + '.' + age;
86
-
87
- if (!this.options.appId) {
88
- const prompts02 = [{
89
- type: 'input',
90
- name: 'appId',
91
- message: 'Your app Id'
92
- },
93
- {
94
- type: 'input',
95
- name: 'appPackage',
96
- message: 'Your app package name',
97
- default: packageDefault
98
- },
99
- {
100
- type: 'input',
101
- name: 'appHomepage',
102
- message: 'Home page url',
103
- default: 'https://fidj.ovh/_/' + age
104
- }
105
- ];
106
-
107
- this.props02 = await this.prompt(prompts02);
108
- } else {
109
- this.props02 = {
110
- appId: this.options.appId,
111
- appPackage: packageDefault,
112
- appHomepage: 'https://fidj.ovh/_/' + age
113
- };
114
- }
27
+ this.answers = await this.prompt([
28
+ ...(!this.options.appname
29
+ ? [
30
+ {
31
+ type: "input",
32
+ name: "name",
33
+ message: "Project name",
34
+ default: "my-fidj-app",
35
+ },
36
+ ]
37
+ : []),
38
+ ...(!this.options["app-id"]
39
+ ? [
40
+ {
41
+ type: "input",
42
+ name: "appId",
43
+ message: "Public fidjId from your owner console",
44
+ },
45
+ ]
46
+ : []),
47
+ ]);
115
48
  }
116
-
117
- async writing() {
118
- if (!this.hasBeenRecordedInFidjOvh) {
119
- return;
120
- }
121
-
122
- let copyAll = true;
123
- if (this.options.appType === 'app2018') {
124
- this.templateName = 'app2018';
125
- } else {
126
- this.templateName = 'app2021';
127
- }
128
-
129
- const now = new Date();
130
- const version = '' + ('' + now.getFullYear()).substr(2) + '.' + (now.getMonth() + 1) + '.' + now.getDate();
131
-
132
- const appArguments = {
133
- appName: this.props.appName,
134
- appNameStrict: this.props.appName.replace(/[^\w\s]/gi, '').replace(/\s+/g, '').replace(/[\. ,:-]+/g, '').toLowerCase(),
135
- appDescription: this.props.appDescription,
136
- appWelcome: this.props.appWelcome,
137
- appContent: this.props.appContent,
138
- appUserName: this.props.appUserName,
139
- appHomepage: this.props02.appHomepage,
140
- appPackage: this.props02.appPackage,
141
- appId: this.props02.appId,
142
- appOptions: this.options.appOptions ? ', {' + this.options.appOptions + '}' : '',
143
- appVersion: version,
144
- appKeywords: 'fidj',
145
- appYear: now.getFullYear(),
146
- appColor: 'white'
147
- };
148
-
149
- this.fs.copyTpl(
150
- this.templatePath(this.templateName + '/*'),
151
- this.destinationPath(),
152
- appArguments
153
- );
154
-
155
- this.fs.copyTpl(
156
- this.templatePath(this.templateName + '/.*'),
157
- this.destinationPath(),
158
- appArguments
159
- );
160
-
161
- this.fs.copyTpl(
162
- this.templatePath(this.templateName + '/src'),
163
- this.destinationPath('src'),
164
- appArguments
49
+ writing() {
50
+ const name = this.options.appname || this.answers.name;
51
+ scaffold(this.destinationPath(name), {
52
+ name,
53
+ title: this.options.title,
54
+ welcome: this.options.welcome,
55
+ description: this.options.description,
56
+ content: this.options.content,
57
+ anonymous: this.options.anonymous,
58
+ module: this.options.module,
59
+ moduleEntry: this.options["module-entry"],
60
+ domain: this.options.domain,
61
+ sdkPath: this.options["sdk-path"],
62
+ appId: this.options["app-id"] || this.answers.appId,
63
+ apiEndpoint: this.options["api-endpoint"],
64
+ });
65
+ this.log(
66
+ `Created ${name}. Copy .env.example to .env, then npm install && npm run build && npm start.`,
165
67
  );
166
-
167
- if (copyAll) {
168
- this.fs.copy(
169
- this.templatePath(this.templateName + '/platforms'),
170
- this.destinationPath('platforms')
171
- );
172
-
173
- this.fs.copy(
174
- this.templatePath(this.templateName + '/resources'),
175
- this.destinationPath('resources')
176
- );
177
-
178
- this.fs.copy(
179
- this.templatePath(this.templateName + '/tests'),
180
- this.destinationPath('tests')
181
- );
182
-
183
- //this.fs.copy(
184
- // this.templatePath(this.templateName + '/www'),
185
- // this.destinationPath('www')
186
- //);
187
- }
188
- }
189
-
190
- async install() {
191
- if (!this.hasBeenRecordedInFidjOvh) {
192
- return;
193
- }
194
- this.npmInstall();
195
- }
196
-
197
- async end() {
198
-
199
68
  }
200
69
  };
@@ -0,0 +1,73 @@
1
+ # Your Fidj TypeScript app
2
+
3
+ A generated TypeScript client with Fidj sign-in and app-scoped privacy. The generator selects the mode from its inputs:
4
+
5
+ - With `--content`: public HTML plus account/privacy controls, built to static `www/` assets and optional `CNAME`. No app backend is required; the client calls Fidj directly.
6
+ - Without `--content`: Studio Notes, with a Node backend enforcing live Owner/Editor roles for private notes.
7
+
8
+ The public title, welcome, HTML content and endpoints are in `app.config.json`. Edit the original generator command and regenerate for repeatable changes. Content HTML is trusted developer source.
9
+
10
+ ## Run
11
+
12
+ Use Node 22 or later. Copy `.env.example` to `.env`, set the public app ID and Fidj API URL, then:
13
+
14
+ ```sh
15
+ npm install
16
+ npm run build
17
+ npm start
18
+ ```
19
+
20
+ Open http://localhost:8200. For content apps, `npm run build-prod` produces static `www/` assets; the Node process is only an optional preview. For Studio Notes, the backend must run for protected operations. Configure Fidj’s allowed origins for your app domain. No app signing key belongs in the browser or this starter’s public configuration.
21
+
22
+ The current unreleased generator requires the matching `@ofidj/node` 3.6.24 SDK. Until publication, generate with `--sdk-path /absolute/path/to/fidj-node/dist` after building that SDK. Local file dependencies belong only in generated development output; use registry dependencies for release.
23
+
24
+ ## Structure
25
+
26
+ - `src/content.ts`: static content app account, live roles and privacy controls.
27
+ - `src/main.ts`: `FidjNodeService.init`, login, browser session and views.
28
+ - `server/index.ts`: `verifyAppSession` on every protected request; live roles decide whether a note can be saved. Changing a role takes effect on the next backend request, even if a browser still displays old roles.
29
+ - `test/server.test.mjs`: fresh HTTP servers verify role changes, revoked/foreign sessions, outage failure, per-user notes and privacy scope.
30
+ - `scripts/build.mjs`: browser and Node builds using [esbuild](https://esbuild.github.io/getting-started/), with a separate TypeScript typecheck.
31
+
32
+ Run `npm test` before changing the template. Every fresh generated app includes the same tests.
33
+
34
+ ## Privacy scope
35
+
36
+ Optional preferences and their history belong to this app. In the static content app, export covers the Fidj-held membership records and no independent app database exists. In Studio Notes, export includes the Fidj membership and the starter’s notes. Leaving through this app removes its Fidj membership and locally held notes. App owners must resolve ownership first.
37
+
38
+ Notes persist in `FIDJ_DATA_DIR`. With the adapter registered below, direct export/departure from Fidj includes these notes. Failed erasure keeps a request in Fidj for automatic retry with backoff; people can also retry explicitly. The API pauses after eight failed automatic attempts and exposes a needs-attention state. Account-wide identity deletion, real terms/purposes and a full production retention policy remain separate integration work. The demo agreement is explicitly a placeholder, not a legal policy.
39
+
40
+ The browser SDK stores the app’s session in this origin’s local storage. Use HTTPS and maintain a strict content security policy when hosting. The backend delegates signature and session-revocation validation to the configured Fidj API and fails closed when it cannot verify a session.
41
+
42
+ ## Local scenario
43
+
44
+ Only when using the loopback API, set `LOCAL_DEMO=true` to show synthetic Alex/Maya/Sam sign-in shortcuts. These accounts must be seeded by your local Fidj API; the starter does not create accounts or seed data remotely. Alex is the owner, and the owner console can grant Maya Editor access.
45
+
46
+ ## Entry flow
47
+
48
+ The generated content app opens on `/#/signin`. Sign in, or choose **Enter anonymously** when enabled by `--anonymous true`, to open `/#/content`, containing the supplied HTML. Signed-in users can open **My privacy** separately. Sign-out and departure return to the sign-in screen. Anonymous content is public; this navigation flow is not a security boundary for static assets.
49
+
50
+ Set `--anonymous false` in the generator command to remove anonymous entry and route unsigned visitors back to sign-in. This controls navigation; static HTML/assets remain public. Put confidential content behind a server-authorized endpoint.
51
+
52
+ ## Application modules
53
+
54
+ When generated with `--module`, successful sign-in opens the copied module configured by `moduleEntry`. It runs under `/module/` on the same origin and must validate sessions/permissions independently. Its entry contains a `fidj-signin` meta URL for returning to this shared sign-in page. Module code is public static output; user data belongs behind authorized APIs. Rebuild the maintained module source and regenerate to update it; never patch its copied files here.
55
+
56
+ ## Connect app data rights
57
+
58
+ Set `FIDJ_PRIVACY_ADAPTER_KEY` to a private random secret of at least 32 characters. Keep it exclusively in server environments; it is separate from an app JWT signing key. Register the app on the Fidj API server:
59
+
60
+ ```json
61
+ {"YOUR_APP_ID":{"url":"https://your-app.example/fidj/privacy","key":"SAME_PRIVATE_RANDOM_SECRET"}}
62
+ ```
63
+
64
+ Set that JSON as `FIDJ_PRIVACY_ADAPTERS` on the API. Endpoint registration is operator-managed in this milestone. HTTPS is required; explicit local mode also permits loopback HTTP. The local workspace launcher configures Studio Notes automatically. Requests contain `appId`, `subject`, `operation` and `requestId`; headers contain a millisecond timestamp and SHA-256 HMAC of `timestamp + "." + JSON.stringify(body)`. Requests older than five minutes are rejected; redirects are not followed. The handler must return the matching `requestId` and `status: "completed"` only after durable success.
65
+
66
+ Keep `FIDJ_DATA_DIR` outside public assets and generated output. Use one writer process per directory. Replace `server/data-store.ts` with a transactional database implementation for multiple instances. Do not weaken the authorization check inside note writes or the atomic erase/receipt transaction. Duplicate erasures preserve later membership data. Minimal receipts contain a hashed subject and completion timestamp; receipts older than 30 days are pruned on the next write. Backups and unregistered external data remain outside this handler’s scope.
67
+
68
+
69
+ ## Check and rehearse
70
+
71
+ After starting the Notes backend with its server-only adapter secret, run `npm run privacy:check`. The signed check confirms export/erase capabilities and writable storage without accessing user records. Override `FIDJ_APP_URL` for a deployed HTTPS backend. Keep this secret out of browser configuration.
72
+
73
+ Run `npm run privacy:rehearse` for an isolated temporary-store HTTP scenario covering live roles, scoped export, persistence, failure and idempotent erasure. It never points at your running data directory. Groups are managed in the Fidj owner console; direct and group roles are checked live by the backend.
@@ -0,0 +1,10 @@
1
+ {
2
+ "appId": "fidj-example",
3
+ "apiEndpoint": "https://api.sandbox.fidj.ovh/v3",
4
+ "dashboardUrl": "https://fidj.ovh",
5
+ "title": "My app",
6
+ "localDemo": false,
7
+ "allowAnonymous": true,
8
+ "moduleEntry": "",
9
+ "description": "A space to explore, with an account that puts you in control."
10
+ }
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ .env
4
+ .env.local
5
+ .fidj-data/
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "fidj-typescript-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc --noEmit && node scripts/build.mjs",
11
+ "start": "node --env-file=.env dist/server.cjs",
12
+ "test": "npm run build && node --test test/*.test.mjs",
13
+ "build-prod": "npm run build",
14
+ "privacy:check": "node --env-file=.env scripts/privacy-check.mjs",
15
+ "privacy:rehearse": "npm run build && node --test test/server.test.mjs"
16
+ },
17
+ "dependencies": {
18
+ "@ofidj/node": "^3.6.24"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^22.0.0",
22
+ "esbuild": "0.28.2",
23
+ "typescript": "5.9.3"
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>My workspace · Fidj</title>
7
+ <link rel="icon" href="/fidj-logo.png" />
8
+ <link rel="stylesheet" href="/main.css" />
9
+ <script type="module" src="/main.js"></script>
10
+ </head>
11
+ <body>
12
+ <div id="app">
13
+ <main><h1>Opening your workspace…</h1></main>
14
+ </div>
15
+ </body>
16
+ </html>