@okalit/cli 0.1.0 → 0.2.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.
Files changed (49) hide show
  1. package/README.md +13 -9
  2. package/lib/cli.js +38 -30
  3. package/package.json +1 -1
  4. package/templates/app/@okalit/Okalit.js +163 -89
  5. package/templates/app/@okalit/channel.js +177 -0
  6. package/templates/app/@okalit/define-element.js +30 -0
  7. package/templates/app/@okalit/i18n.js +88 -53
  8. package/templates/app/@okalit/index.js +8 -10
  9. package/templates/app/@okalit/mixins.js +106 -0
  10. package/templates/app/@okalit/performance.js +211 -0
  11. package/templates/app/@okalit/router-outlet.js +66 -0
  12. package/templates/app/@okalit/router.js +240 -0
  13. package/templates/app/@okalit/service.js +318 -23
  14. package/templates/app/index.html +0 -1
  15. package/templates/app/package.json +2 -3
  16. package/templates/app/public/i18n/en.json +47 -1
  17. package/templates/app/public/i18n/es.json +47 -1
  18. package/templates/app/src/{app.routes.ts → app.routes.js} +1 -1
  19. package/templates/app/src/channels/example.channel.js +15 -0
  20. package/templates/app/src/components/lazy-widget.js +13 -0
  21. package/templates/app/src/guards/auth.guard.js +17 -0
  22. package/templates/app/src/layouts/app-layout.js +75 -0
  23. package/templates/app/src/main-app.js +19 -9
  24. package/templates/app/src/modules/example/example.module.js +8 -3
  25. package/templates/app/src/modules/example/example.routes.js +27 -4
  26. package/templates/app/src/modules/example/pages/detail/example-detail.js +21 -0
  27. package/templates/app/src/modules/example/pages/home/example-home.js +39 -0
  28. package/templates/app/src/modules/example/pages/lifecycle/example-lifecycle.js +74 -0
  29. package/templates/app/src/modules/example/pages/performance/example-performance.js +59 -0
  30. package/templates/app/src/modules/example/pages/services/example-services.js +80 -0
  31. package/templates/app/src/services/rickandmorty.service.js +17 -0
  32. package/templates/app/src/services/user.service.js +33 -0
  33. package/templates/app/src/styles/global.scss +250 -0
  34. package/templates/app/src/styles/index.css +11 -2
  35. package/templates/app/vite.config.js +2 -0
  36. package/templates/app/@okalit/AppMixin.js +0 -29
  37. package/templates/app/@okalit/EventBus.js +0 -152
  38. package/templates/app/@okalit/ModuleMixin.js +0 -7
  39. package/templates/app/@okalit/OkalitService.js +0 -145
  40. package/templates/app/@okalit/defineElement.js +0 -65
  41. package/templates/app/@okalit/idle.js +0 -40
  42. package/templates/app/@okalit/lazy.js +0 -32
  43. package/templates/app/@okalit/okalit-router.js +0 -309
  44. package/templates/app/@okalit/trigger.js +0 -14
  45. package/templates/app/@okalit/viewport.js +0 -69
  46. package/templates/app/@okalit/when.js +0 -40
  47. package/templates/app/public/lit.svg +0 -1
  48. package/templates/app/src/modules/example/pages/example.page.js +0 -43
  49. package/templates/app/src/modules/example/pages/example.page.scss +0 -76
@@ -1,3 +1,49 @@
1
1
  {
2
- "WELCOME": "Bienvenido a la plantilla de Okalit"
2
+ "APP": {
3
+ "TITLE": "Okalit Starter",
4
+ "SUBTITLE": "Un framework moderno de web components"
5
+ },
6
+ "NAV": {
7
+ "HOME": "Inicio",
8
+ "LIFECYCLE": "Ciclo de vida",
9
+ "SERVICES": "Servicios",
10
+ "PERFORMANCE": "Rendimiento",
11
+ "DETAIL": "Detalle {{ id }}"
12
+ },
13
+ "HOME": {
14
+ "HEADING": "Panel principal",
15
+ "COUNTER": "Contador compartido",
16
+ "COUNTER_HINT": "El contador debe ser > 2 para acceder a la página de detalle (demo de guards).",
17
+ "RESET": "Reiniciar",
18
+ "GO_DETAIL": "Ir al Detalle {{ id }}",
19
+ "GO_LIFECYCLE": "Demo Ciclo de vida",
20
+ "GO_SERVICES": "Demo Servicios",
21
+ "GO_PERF": "Demo Rendimiento"
22
+ },
23
+ "LIFECYCLE": {
24
+ "HEADING": "Hooks del ciclo de vida",
25
+ "LOG": "Registro de eventos",
26
+ "CLEAR": "Limpiar",
27
+ "CHANGE_PROP": "Cambiar propiedad name"
28
+ },
29
+ "SERVICES": {
30
+ "HEADING": "Servicios y GraphQL",
31
+ "REST_TITLE": "REST — Usuarios de JSONPlaceholder",
32
+ "GQL_TITLE": "GraphQL — Personajes de Rick & Morty",
33
+ "LOADING": "Cargando…",
34
+ "ERROR": "Error al cargar datos."
35
+ },
36
+ "PERF": {
37
+ "HEADING": "Componentes de rendimiento",
38
+ "IDLE_LABEL": "Cargado vía <o-idle> (requestIdleCallback)",
39
+ "WHEN_LABEL": "Cargado vía <o-when> (condición)",
40
+ "VIEWPORT_LABEL": "Cargado vía <o-viewport> (desplaza hacia abajo)",
41
+ "TOGGLE": "Activar condición",
42
+ "SCROLL_HINT": "Desplaza hacia abajo para activar <o-viewport>…"
43
+ },
44
+ "DETAIL": {
45
+ "HEADING": "Página de detalle",
46
+ "VIEWING": "Viendo elemento",
47
+ "BACK": "Volver al inicio"
48
+ }
3
49
  }
@@ -6,5 +6,5 @@ export default [
6
6
  component: "example-module",
7
7
  import: () => import("./modules/example/example.module.js"),
8
8
  children: ExampleModuleRoutes,
9
- }
9
+ },
10
10
  ];
@@ -0,0 +1,15 @@
1
+ import { defineChannel } from '@okalit';
2
+
3
+ // Counter: persisted in localStorage, lives across the entire app
4
+ export const CounterChannel = defineChannel('app:counter', {
5
+ initialValue: 0,
6
+ persist: 'local',
7
+ scope: 'app',
8
+ });
9
+
10
+ // Navigation log: ephemeral channel to broadcast interceptor events
11
+ export const NavLogChannel = defineChannel('app:navlog', {
12
+ initialValue: [],
13
+ persist: 'memory',
14
+ scope: 'app',
15
+ });
@@ -0,0 +1,13 @@
1
+ import { defineElement, Okalit, html } from "@okalit";
2
+
3
+ @defineElement({ tag: "lazy-widget" })
4
+ export class LazyWidget extends Okalit {
5
+ render() {
6
+ return html`
7
+ <div style="padding:16px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px">
8
+ <strong>Lazy Widget loaded!</strong>
9
+ <p style="margin:4px 0 0;font-size:0.85rem;color:#555">This component was dynamically imported.</p>
10
+ </div>
11
+ `;
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Blocks navigation unless the counter value is greater than 2.
3
+ * Reads directly from localStorage (where CounterChannel persists).
4
+ *
5
+ * Guards run BEFORE the dynamic import — no code is loaded if they fail.
6
+ * Return: true (allow), false (block), or string (redirect path).
7
+ */
8
+ export function authGuard() {
9
+ const raw = localStorage.getItem('okalit:channel:app:counter');
10
+ const count = raw !== null ? JSON.parse(raw) : 0;
11
+
12
+ if (count <= 2) {
13
+ return '/';
14
+ }
15
+
16
+ return true;
17
+ }
@@ -0,0 +1,75 @@
1
+ import { defineElement, Okalit, html, signal, t, getI18n, Router } from '@okalit';
2
+ import { NavLogChannel } from '@channels/example.channel.js';
3
+
4
+ import global from '@styles/global.scss?inline';
5
+
6
+ @defineElement({
7
+ tag: 'app-layout',
8
+ styles: [global],
9
+ })
10
+ export class AppLayout extends Okalit {
11
+ static channels = {
12
+ navLog: NavLogChannel(),
13
+ };
14
+
15
+ showLog = signal(false);
16
+
17
+ onInit() {
18
+ this._removeInterceptor = Router.getInstance().addInterceptor((match, path) => {
19
+ const entry = `[${new Date().toLocaleTimeString()}] → ${path}`;
20
+ this.navLog.set([...this.navLog.value, entry]);
21
+ return true;
22
+ });
23
+ }
24
+
25
+ onDestroy() {
26
+ this._removeInterceptor?.();
27
+ }
28
+
29
+ _nav(path) {
30
+ Router.getInstance()?.navigate(path);
31
+ }
32
+
33
+ render() {
34
+ const locale = getI18n()?.locale.value;
35
+ const i18n = getI18n();
36
+ const logs = this.navLog.value;
37
+
38
+ return html`
39
+ <header class="app-header">
40
+ <div class="app-brand">
41
+ <h1>${t('APP.TITLE')}</h1>
42
+ <span class="app-subtitle">${t('APP.SUBTITLE')}</span>
43
+ </div>
44
+ <nav class="app-nav">
45
+ <a @click=${() => this._nav('/')}>${t('NAV.HOME')}</a>
46
+ <a @click=${() => this._nav('/lifecycle')}>${t('NAV.LIFECYCLE')}</a>
47
+ <a @click=${() => this._nav('/services')}>${t('NAV.SERVICES')}</a>
48
+ <a @click=${() => this._nav('/performance')}>${t('NAV.PERFORMANCE')}</a>
49
+ </nav>
50
+ <div class="locale-switch">
51
+ <button class=${locale === 'en' ? 'active' : ''} @click=${() => i18n?.setLocale('en')}>EN</button>
52
+ <button class=${locale === 'es' ? 'active' : ''} @click=${() => i18n?.setLocale('es')}>ES</button>
53
+ </div>
54
+ </header>
55
+ <main class="app-content">
56
+ <slot></slot>
57
+ </main>
58
+ <footer class="app-footer">
59
+ <div class="footer-bar">
60
+ <button class="footer-toggle" @click=${() => this.showLog.value = !this.showLog.value}>
61
+ Interceptor Log (${logs.length})
62
+ </button>
63
+ ${logs.length > 0 ? html`
64
+ <button class="footer-clear" @click=${() => this.navLog.set([])}>Clear</button>
65
+ ` : null}
66
+ </div>
67
+ ${this.showLog.value && logs.length > 0 ? html`
68
+ <div class="log-panel footer-log">
69
+ ${logs.map(l => html`<div class="log-entry">${l}</div>`)}
70
+ </div>
71
+ ` : null}
72
+ </footer>
73
+ `;
74
+ }
75
+ }
@@ -1,13 +1,23 @@
1
- import { Okalit, defineElement, AppMixin } from '@okalit';
2
- import routes from './app.routes.ts';
1
+ import { defineElement, Okalit, html, AppMixin } from '@okalit';
2
+ import routes from './app.routes.js';
3
3
 
4
- @defineElement({ tag: 'main-app' })
4
+ import '@layouts/app-layout.js';
5
+
6
+ @defineElement({
7
+ tag: 'main-app',
8
+ })
5
9
  export class MainApp extends AppMixin(Okalit) {
6
- _appConfig = {
7
- routes,
8
- i18n: {
9
- default: 'es',
10
- locales: ['es', 'en'],
11
- },
10
+ static routes = routes;
11
+ static i18n = {
12
+ default: 'en',
13
+ locales: ['es', 'en'],
14
+ }
15
+
16
+ render() {
17
+ return html`
18
+ <app-layout>
19
+ <okalit-router></okalit-router>
20
+ </app-layout>
21
+ `;
12
22
  }
13
23
  }
@@ -1,4 +1,9 @@
1
- import { ModuleMixin, Okalit, defineElement } from '@okalit';
1
+ import { defineElement, Okalit, ModuleMixin } from '@okalit';
2
2
 
3
- @defineElement({ tag: 'example-module' })
4
- export class ExampleModule extends ModuleMixin(Okalit) {}
3
+ import global from '@styles/global.scss?inline';
4
+
5
+ @defineElement({
6
+ tag: 'example-module',
7
+ styles: [global],
8
+ })
9
+ export class ExampleModule extends ModuleMixin(Okalit) {}
@@ -1,7 +1,30 @@
1
+ import { authGuard } from "@guards/auth.guard.js";
2
+
1
3
  export default [
2
4
  {
3
- path: '',
4
- component: 'example-page',
5
- import: () => import('./pages/example.page.js')
6
- }
5
+ path: "/",
6
+ component: "example-home",
7
+ import: () => import("./pages/home/example-home.js"),
8
+ },
9
+ {
10
+ path: "/lifecycle",
11
+ component: "example-lifecycle",
12
+ import: () => import("./pages/lifecycle/example-lifecycle.js"),
13
+ },
14
+ {
15
+ path: "/services",
16
+ component: "example-services",
17
+ import: () => import("./pages/services/example-services.js"),
18
+ },
19
+ {
20
+ path: "/performance",
21
+ component: "example-performance",
22
+ import: () => import("./pages/performance/example-performance.js"),
23
+ },
24
+ {
25
+ path: "/detail/:id",
26
+ component: "example-detail",
27
+ import: () => import("./pages/detail/example-detail.js"),
28
+ guards: [authGuard],
29
+ },
7
30
  ];
@@ -0,0 +1,21 @@
1
+ import { defineElement, Okalit, html, PageMixin, t } from "@okalit";
2
+
3
+ import global from "@styles/global.scss?inline";
4
+
5
+ @defineElement({
6
+ tag: "example-detail",
7
+ styles: [global],
8
+ })
9
+ export class ExampleDetail extends PageMixin(Okalit) {
10
+ render() {
11
+ const id = this.routeParams.id;
12
+ return html`
13
+ <h2>${t('DETAIL.HEADING')}</h2>
14
+ <div class="card">
15
+ <p>${t('DETAIL.VIEWING')}: <strong>#${id}</strong></p>
16
+ <p class="hint">This page is protected by a guard. Counter must be > 2.</p>
17
+ </div>
18
+ <button @click=${() => this.navigate("/")}>${t('DETAIL.BACK')}</button>
19
+ `;
20
+ }
21
+ }
@@ -0,0 +1,39 @@
1
+ import { defineElement, Okalit, html, signal, PageMixin, t } from "@okalit";
2
+ import { CounterChannel } from "@channels/example.channel.js";
3
+
4
+ import global from "@styles/global.scss?inline";
5
+
6
+ @defineElement({
7
+ tag: "example-home",
8
+ styles: [global],
9
+ })
10
+ export class ExampleHome extends PageMixin(Okalit) {
11
+ static channels = {
12
+ counter: CounterChannel(),
13
+ };
14
+
15
+ render() {
16
+ return html`
17
+ <h2>${t('HOME.HEADING')}</h2>
18
+
19
+ <div class="card">
20
+ <h3>${t('HOME.COUNTER')}</h3>
21
+ <div class="count">${this.counter.value}</div>
22
+ <div class="controls-row">
23
+ <button @click=${() => this.counter.set(this.counter.value + 1)}>+1</button>
24
+ <button @click=${() => this.counter.set(this.counter.value - 1)}>-1</button>
25
+ <button @click=${() => this.counter.set(0)}>${t('HOME.RESET')}</button>
26
+ </div>
27
+ <p class="hint">${t('HOME.COUNTER_HINT')}</p>
28
+ </div>
29
+
30
+ <h3>Navigation</h3>
31
+ <div class="controls-row">
32
+ <button class="primary" @click=${() => this.navigate('/detail/42')}>${t('HOME.GO_DETAIL', { id: '42' })}</button>
33
+ <button @click=${() => this.navigate('/lifecycle')}>${t('HOME.GO_LIFECYCLE')}</button>
34
+ <button @click=${() => this.navigate('/services')}>${t('HOME.GO_SERVICES')}</button>
35
+ <button @click=${() => this.navigate('/performance')}>${t('HOME.GO_PERF')}</button>
36
+ </div>
37
+ `;
38
+ }
39
+ }
@@ -0,0 +1,74 @@
1
+ import { defineElement, Okalit, html, signal, PageMixin, t } from "@okalit";
2
+
3
+ import global from "@styles/global.scss?inline";
4
+
5
+ const names = ['Ada', 'Grace', 'Alan', 'Linus', 'Margaret'];
6
+ let idx = 0;
7
+
8
+ @defineElement({
9
+ tag: "example-lifecycle",
10
+ styles: [global],
11
+ props: [
12
+ { name: { type: String, value: 'World' } },
13
+ ],
14
+ })
15
+ export class ExampleLifecycle extends PageMixin(Okalit) {
16
+ logs = signal([]);
17
+
18
+ _log(msg) {
19
+ this.logs.value = [...this.logs.value, `[${new Date().toLocaleTimeString()}] ${msg}`];
20
+ }
21
+
22
+ onInit() {
23
+ this._log('onInit — component initialized');
24
+ }
25
+
26
+ onChange(changes) {
27
+ for (const [prop, { previous, current }] of Object.entries(changes)) {
28
+ this._log(`onChange — ${prop}: "${previous}" → "${current}"`);
29
+ }
30
+ }
31
+
32
+ onBeforeRender() {
33
+ // logged silently to avoid noise — fires every render
34
+ }
35
+
36
+ onAfterRender() {
37
+ // same as above
38
+ }
39
+
40
+ onDestroy() {
41
+ console.log('[lifecycle] onDestroy — component removed from DOM');
42
+ }
43
+
44
+ _changeName() {
45
+ idx = (idx + 1) % names.length;
46
+ this.name.value = names[idx];
47
+ }
48
+
49
+ render() {
50
+ return html`
51
+ <h2>${t('LIFECYCLE.HEADING')}</h2>
52
+
53
+ <div class="card">
54
+ <p>Current <code>name</code> prop: <strong>${this.name.value}</strong></p>
55
+ <div class="controls-row">
56
+ <button class="primary" @click=${() => this._changeName()}>${t('LIFECYCLE.CHANGE_PROP')}</button>
57
+ </div>
58
+ <p class="hint">Each change triggers onChange() → logged below.</p>
59
+ </div>
60
+
61
+ <h3>${t('LIFECYCLE.LOG')}</h3>
62
+ <div class="log-panel">
63
+ ${this.logs.value.length === 0
64
+ ? html`<span class="hint">No events yet…</span>`
65
+ : this.logs.value.map(l => html`<div class="log-entry">${l}</div>`)
66
+ }
67
+ </div>
68
+ <div class="controls-row" style="margin-top:12px">
69
+ <button @click=${() => this.logs.value = []}>${t('LIFECYCLE.CLEAR')}</button>
70
+ <button @click=${() => this.navigate('/')}>← ${t('NAV.HOME')}</button>
71
+ </div>
72
+ `;
73
+ }
74
+ }
@@ -0,0 +1,59 @@
1
+ import { defineElement, Okalit, html, signal, PageMixin, t } from "@okalit";
2
+ import '@okalit/performance.js';
3
+
4
+ import global from "@styles/global.scss?inline";
5
+
6
+ const loadWidget = () => import('@components/lazy-widget.js');
7
+
8
+ @defineElement({
9
+ tag: "example-performance",
10
+ styles: [global],
11
+ })
12
+ export class ExamplePerformance extends PageMixin(Okalit) {
13
+ showConditional = signal(false);
14
+
15
+ render() {
16
+ return html`
17
+ <h2>${t('PERF.HEADING')}</h2>
18
+
19
+ <div class="card">
20
+ <h3>&lt;o-idle&gt;</h3>
21
+ <p class="hint">${t('PERF.IDLE_LABEL')}</p>
22
+ <o-idle .loader=${loadWidget}>
23
+ <lazy-widget></lazy-widget>
24
+ <p slot="fallback" class="fallback">⏳ Waiting for idle…</p>
25
+ </o-idle>
26
+ </div>
27
+
28
+ <div class="card">
29
+ <h3>&lt;o-when&gt;</h3>
30
+ <p class="hint">${t('PERF.WHEN_LABEL')}</p>
31
+ <div class="controls-row" style="margin-bottom:12px">
32
+ <button class="primary" @click=${() => this.showConditional.value = true}>
33
+ ${t('PERF.TOGGLE')}
34
+ </button>
35
+ <span class="hint">condition = ${this.showConditional.value ? 'true' : 'false'}</span>
36
+ </div>
37
+ <o-when .condition=${this.showConditional.value} .loader=${loadWidget}>
38
+ <lazy-widget></lazy-widget>
39
+ <p slot="fallback" class="fallback">⏳ Waiting for condition…</p>
40
+ </o-when>
41
+ </div>
42
+
43
+ <div class="card">
44
+ <h3>&lt;o-viewport&gt;</h3>
45
+ <p class="hint">${t('PERF.VIEWPORT_LABEL')}</p>
46
+ <p class="hint">${t('PERF.SCROLL_HINT')}</p>
47
+ <div class="spacer"></div>
48
+ <o-viewport .loader=${loadWidget}>
49
+ <lazy-widget></lazy-widget>
50
+ <p slot="fallback" class="fallback">⏳ Waiting for viewport…</p>
51
+ </o-viewport>
52
+ </div>
53
+
54
+ <div class="controls-row" style="margin-top:12px">
55
+ <button @click=${() => this.navigate('/')}>← ${t('NAV.HOME')}</button>
56
+ </div>
57
+ `;
58
+ }
59
+ }
@@ -0,0 +1,80 @@
1
+ import { defineElement, Okalit, html, signal, PageMixin, t, inject } from "@okalit";
2
+
3
+ import '@services/user.service.js';
4
+ import '@services/rickandmorty.service.js';
5
+
6
+ import global from "@styles/global.scss?inline";
7
+
8
+ @defineElement({
9
+ tag: "example-services",
10
+ styles: [global],
11
+ })
12
+ export class ExampleServices extends PageMixin(Okalit) {
13
+ userApi = inject('user');
14
+ gqlApi = inject('rickandmorty');
15
+
16
+ users = signal([]);
17
+ characters = signal([]);
18
+ restLoading = signal(false);
19
+ gqlLoading = signal(false);
20
+ restError = signal(null);
21
+ gqlError = signal(null);
22
+
23
+ onInit() {
24
+ this.userApi.getUsers().fire({
25
+ onLoading: (v) => this.restLoading.value = v,
26
+ onSuccess: (data) => this.users.value = data.slice(0, 6),
27
+ onError: (err) => this.restError.value = err,
28
+ });
29
+
30
+ this.gqlApi.getCharacters().fire({
31
+ onLoading: (v) => this.gqlLoading.value = v,
32
+ onSuccess: (data) => this.characters.value = data.characters.results,
33
+ onError: (err) => this.gqlError.value = err,
34
+ });
35
+ }
36
+
37
+ render() {
38
+ return html`
39
+ <h2>${t('SERVICES.HEADING')}</h2>
40
+
41
+ <div class="card">
42
+ <h3>${t('SERVICES.REST_TITLE')}</h3>
43
+ <p class="hint">OkalitService + cache: true + fire({ onLoading, onSuccess, onError })</p>
44
+ ${this.restLoading.value
45
+ ? html`<p class="fallback">${t('SERVICES.LOADING')}</p>`
46
+ : this.restError.value
47
+ ? html`<p class="fallback">${t('SERVICES.ERROR')}</p>`
48
+ : html`
49
+ <ul class="data-list">
50
+ ${this.users.value.map(u => html`
51
+ <li><strong>${u.name}</strong> — ${u.email}</li>
52
+ `)}
53
+ </ul>
54
+ `
55
+ }
56
+ </div>
57
+
58
+ <div class="card">
59
+ <h3>${t('SERVICES.GQL_TITLE')}</h3>
60
+ <p class="hint">OkalitGraphqlService + .query() + cache</p>
61
+ ${this.gqlLoading.value
62
+ ? html`<p class="fallback">${t('SERVICES.LOADING')}</p>`
63
+ : this.gqlError.value
64
+ ? html`<p class="fallback">${t('SERVICES.ERROR')}</p>`
65
+ : html`
66
+ <ul class="data-list">
67
+ ${this.characters.value.map(c => html`
68
+ <li><strong>${c.name}</strong></li>
69
+ `)}
70
+ </ul>
71
+ `
72
+ }
73
+ </div>
74
+
75
+ <div class="controls-row" style="margin-top:12px">
76
+ <button @click=${() => this.navigate('/')}>← ${t('NAV.HOME')}</button>
77
+ </div>
78
+ `;
79
+ }
80
+ }
@@ -0,0 +1,17 @@
1
+ import { OkalitGraphqlService, service } from '@okalit';
2
+
3
+ @service('rickandmorty')
4
+ export class RickAndMortyService extends OkalitGraphqlService {
5
+ constructor() {
6
+ super();
7
+ this.configure({
8
+ endpoint: 'https://rickandmortyapi.com/graphql',
9
+ cache: true,
10
+ cacheTTL: 120_000,
11
+ });
12
+ }
13
+
14
+ getCharacters() {
15
+ return this.query(`{ characters(page: 2, filter: { name: "rick" }) { results { name } } }`);
16
+ }
17
+ }
@@ -0,0 +1,33 @@
1
+ import { OkalitService, service } from '@okalit';
2
+
3
+ @service('user')
4
+ export class UserService extends OkalitService {
5
+ constructor() {
6
+ super();
7
+ this.configure({
8
+ baseUrl: 'https://jsonplaceholder.typicode.com',
9
+ cache: true,
10
+ cacheTTL: 60_000,
11
+ });
12
+ }
13
+
14
+ getUsers() {
15
+ return this.get('/users');
16
+ }
17
+
18
+ getUserById(id) {
19
+ return this.get(`/users/${id}`);
20
+ }
21
+
22
+ createUser(data) {
23
+ return this.post('/users', data);
24
+ }
25
+
26
+ updateUser(id, data) {
27
+ return this.put(`/users/${id}`, data);
28
+ }
29
+
30
+ deleteUser(id) {
31
+ return this.delete(`/users/${id}`);
32
+ }
33
+ }