@datamagik/cli 0.1.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 (86) hide show
  1. package/LICENSE +21 -0
  2. package/assets/dm-script-globals.d.ts +181 -0
  3. package/dist/api.d.ts +247 -0
  4. package/dist/api.js +200 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/commands/add.d.ts +28 -0
  7. package/dist/commands/add.js +260 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/dev.d.ts +25 -0
  10. package/dist/commands/dev.js +113 -0
  11. package/dist/commands/dev.js.map +1 -0
  12. package/dist/commands/init.d.ts +23 -0
  13. package/dist/commands/init.js +136 -0
  14. package/dist/commands/init.js.map +1 -0
  15. package/dist/commands/login.d.ts +16 -0
  16. package/dist/commands/login.js +42 -0
  17. package/dist/commands/login.js.map +1 -0
  18. package/dist/commands/publish.d.ts +23 -0
  19. package/dist/commands/publish.js +113 -0
  20. package/dist/commands/publish.js.map +1 -0
  21. package/dist/commands/script.d.ts +69 -0
  22. package/dist/commands/script.js +289 -0
  23. package/dist/commands/script.js.map +1 -0
  24. package/dist/commands/sql.d.ts +28 -0
  25. package/dist/commands/sql.js +124 -0
  26. package/dist/commands/sql.js.map +1 -0
  27. package/dist/commands/typegen.d.ts +13 -0
  28. package/dist/commands/typegen.js +50 -0
  29. package/dist/commands/typegen.js.map +1 -0
  30. package/dist/config.d.ts +45 -0
  31. package/dist/config.js +118 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/credentials.d.ts +17 -0
  34. package/dist/credentials.js +49 -0
  35. package/dist/credentials.js.map +1 -0
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +268 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/scriptfile.d.ts +10 -0
  40. package/dist/scriptfile.js +91 -0
  41. package/dist/scriptfile.js.map +1 -0
  42. package/dist/sqlfile.d.ts +9 -0
  43. package/dist/sqlfile.js +75 -0
  44. package/dist/sqlfile.js.map +1 -0
  45. package/dist/typegen/emit.d.ts +22 -0
  46. package/dist/typegen/emit.js +255 -0
  47. package/dist/typegen/emit.js.map +1 -0
  48. package/dist/typegen/meta.d.ts +84 -0
  49. package/dist/typegen/meta.js +209 -0
  50. package/dist/typegen/meta.js.map +1 -0
  51. package/package.json +35 -0
  52. package/templates/showcase/README.md +55 -0
  53. package/templates/showcase/_gitignore +4 -0
  54. package/templates/showcase/dm.config.json +16 -0
  55. package/templates/showcase/env.d.ts +7 -0
  56. package/templates/showcase/index.html +12 -0
  57. package/templates/showcase/package.json +25 -0
  58. package/templates/showcase/src/App.vue +67 -0
  59. package/templates/showcase/src/assets/datamagik-logo.png +0 -0
  60. package/templates/showcase/src/components/ShowcasePanel.vue +47 -0
  61. package/templates/showcase/src/components/panels/ContextPanel.vue +35 -0
  62. package/templates/showcase/src/components/panels/NavigatePanel.vue +38 -0
  63. package/templates/showcase/src/components/panels/OutputPanel.vue +50 -0
  64. package/templates/showcase/src/components/panels/PrintPanel.vue +68 -0
  65. package/templates/showcase/src/components/panels/QueryPanel.vue +52 -0
  66. package/templates/showcase/src/components/panels/ScriptPanel.vue +55 -0
  67. package/templates/showcase/src/components/panels/SerialPanel.vue +64 -0
  68. package/templates/showcase/src/dm-script-types.d.ts +13 -0
  69. package/templates/showcase/src/dm.generated.ts +65 -0
  70. package/templates/showcase/src/format.ts +13 -0
  71. package/templates/showcase/src/main.ts +5 -0
  72. package/templates/showcase/src/style.css +134 -0
  73. package/templates/showcase/tsconfig.json +17 -0
  74. package/templates/showcase/vite.config.ts +9 -0
  75. package/templates/simple/README.md +37 -0
  76. package/templates/simple/_gitignore +4 -0
  77. package/templates/simple/dm.config.json +10 -0
  78. package/templates/simple/env.d.ts +7 -0
  79. package/templates/simple/index.html +12 -0
  80. package/templates/simple/package.json +25 -0
  81. package/templates/simple/src/App.vue +71 -0
  82. package/templates/simple/src/dm.generated.ts +32 -0
  83. package/templates/simple/src/main.ts +5 -0
  84. package/templates/simple/src/style.css +63 -0
  85. package/templates/simple/tsconfig.json +17 -0
  86. package/templates/simple/vite.config.ts +9 -0
@@ -0,0 +1,65 @@
1
+ /* eslint-disable */
2
+ // ----------------------------------------------------------------------------
3
+ // Generated by `dm typegen` — DO NOT EDIT.
4
+ // This is a starter STUB so the showcase type-checks before you connect. Set a
5
+ // real "appId" + resource ids in dm.config.json (use `dm add`) and run
6
+ // `dm typegen`; that overwrites this file with types fetched from your tenant.
7
+ // ----------------------------------------------------------------------------
8
+ import { createDm } from '@datamagik/app-sdk';
9
+ import type { AliasRegistry, ScriptTypeOf } from '@datamagik/app-sdk';
10
+
11
+ /** Row of lookup table "Parts" (replaced by real columns on `dm typegen`). */
12
+ export interface PartsRow {
13
+ display_text: string;
14
+ unit_cost: number;
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ /** Parameters of ODBC query "Open Orders". */
19
+ export interface OpenOrdersParams {
20
+ status?: string;
21
+ }
22
+
23
+ /** Row of ODBC query "Open Orders" — columns are not statically declared. */
24
+ export type OpenOrdersRow = Record<string, unknown>;
25
+
26
+ /** Generation context for serial series "Lot Serial". */
27
+ export interface LotSerialContext {
28
+ PART?: string;
29
+ LINE?: string;
30
+ }
31
+
32
+ /**
33
+ * Typed alias surface for this app. Passed as the generic of `createDm` so
34
+ * every alias autocompletes in any TypeScript-aware editor.
35
+ */
36
+ export interface DmGenerated {
37
+ tables: {
38
+ parts: PartsRow;
39
+ };
40
+ odbc: {
41
+ openOrders: { params: OpenOrdersParams; row: OpenOrdersRow };
42
+ };
43
+ scripts: {
44
+ // IO comes from the DmScriptTypes augmentation in src/dm-script-types.d.ts.
45
+ postReceipt: ScriptTypeOf<'postReceipt'>;
46
+ };
47
+ serials: {
48
+ lotSerial: { context: LotSerialContext };
49
+ };
50
+ printers: {
51
+ line1Zebra: { formats: 'zpl' | 'html' };
52
+ };
53
+ }
54
+
55
+ /** Runtime alias → { type, id } registry (placeholder ids — replace via `dm add`). */
56
+ export const dmRegistry: AliasRegistry = {
57
+ line1Zebra: { type: 'printer', id: 1 },
58
+ lotSerial: { type: 'serial_series', id: 1 },
59
+ openOrders: { type: 'odbc_query', id: 2 },
60
+ parts: { type: 'lookup_table', id: 1 },
61
+ postReceipt: { type: 'script', id: 3 },
62
+ };
63
+
64
+ /** Ready-to-use, fully typed SDK instance for this app. */
65
+ export const dm = createDm<DmGenerated>(dmRegistry);
@@ -0,0 +1,13 @@
1
+ import { DmError } from '@datamagik/app-sdk';
2
+
3
+ /** Human-readable one-liner for any thrown value. */
4
+ export function fmtErr(e: unknown): string {
5
+ if (e instanceof DmError) return `${e.code}: ${e.message}`;
6
+ if (e instanceof Error) return e.message;
7
+ return String(e);
8
+ }
9
+
10
+ /** Pretty-print a value for a result box. */
11
+ export function pretty(v: unknown): string {
12
+ return typeof v === 'string' ? v : JSON.stringify(v, null, 2);
13
+ }
@@ -0,0 +1,5 @@
1
+ import { createApp } from 'vue';
2
+ import App from './App.vue';
3
+ import './style.css';
4
+
5
+ createApp(App).mount('#app');
@@ -0,0 +1,134 @@
1
+ :root {
2
+ /* DataMagik brand palette (matches the platform). */
3
+ --dm-purple: #9333ea;
4
+ --dm-purple-light: #a855f7;
5
+ --dm-purple-dark: #7e22ce;
6
+ --dm-purple-50: #faf5ff;
7
+ --dm-purple-100: #f3e8ff;
8
+
9
+ --dm-bg: #f9fafb;
10
+ --dm-card: #ffffff;
11
+ --dm-border: #e5e7eb;
12
+ --dm-border-soft: #f3f4f6;
13
+
14
+ --dm-ink: #111827;
15
+ --dm-ink-soft: #6b7280;
16
+ --dm-ink-faint: #9ca3af;
17
+
18
+ --dm-ok: #059669;
19
+ --dm-ok-bg: #ecfdf5;
20
+ --dm-ok-border: #a7f3d0;
21
+ --dm-err: #dc2626;
22
+ --dm-err-bg: #fef2f2;
23
+ --dm-err-border: #fecaca;
24
+
25
+ --dm-code-bg: #1e1b2e;
26
+ --dm-code-ink: #e9d5ff;
27
+
28
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
29
+ color: var(--dm-ink);
30
+ -webkit-font-smoothing: antialiased;
31
+ }
32
+
33
+ * { box-sizing: border-box; }
34
+ body { margin: 0; background: var(--dm-bg); }
35
+ code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
36
+
37
+ .shell { max-width: 1040px; margin: 0 auto; padding: 1.5rem 1rem 4rem; }
38
+
39
+ /* ---- Header ---- */
40
+ .app-header {
41
+ display: flex; align-items: center; gap: 1rem;
42
+ background: linear-gradient(135deg, var(--dm-purple), var(--dm-purple-dark));
43
+ color: #fff; border-radius: 1rem; padding: 1.25rem 1.5rem;
44
+ box-shadow: 0 10px 25px -10px rgba(147, 51, 234, 0.5);
45
+ }
46
+ .app-header img.logo { height: 38px; width: auto; }
47
+ .app-header .titles { min-width: 0; flex: 1; }
48
+ .app-header h1 { font-size: 1.4rem; font-weight: 700; margin: 0; line-height: 1.2; }
49
+ .app-header p { margin: 0.15rem 0 0; font-size: 0.85rem; color: rgba(255, 255, 255, 0.85); }
50
+ .app-header .status {
51
+ display: inline-flex; align-items: center; gap: 0.45rem;
52
+ background: rgba(255, 255, 255, 0.15); border: 1px solid rgba(255, 255, 255, 0.25);
53
+ border-radius: 999px; padding: 0.35rem 0.75rem; font-size: 0.8rem; font-weight: 600;
54
+ white-space: nowrap;
55
+ }
56
+ .status .dot { width: 0.55rem; height: 0.55rem; border-radius: 50%; background: #fde68a; }
57
+ .status .dot.ok { background: #6ee7b7; }
58
+ .status .dot.err { background: #fca5a5; }
59
+
60
+ .notice {
61
+ margin: 1rem 0 0; padding: 0.75rem 1rem; font-size: 0.85rem;
62
+ background: var(--dm-purple-50); border: 1px solid var(--dm-purple-100);
63
+ color: #6b21a8; border-radius: 0.75rem;
64
+ }
65
+ .notice code { color: var(--dm-purple-dark); font-weight: 600; }
66
+
67
+ /* ---- Panel grid ---- */
68
+ .grid {
69
+ display: grid; gap: 1rem; margin-top: 1.25rem;
70
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
71
+ }
72
+
73
+ .panel {
74
+ background: var(--dm-card); border: 1px solid var(--dm-border-soft);
75
+ border-radius: 0.85rem; padding: 1.1rem 1.15rem;
76
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); display: flex; flex-direction: column;
77
+ }
78
+ .panel-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.35rem; }
79
+ .panel-icon {
80
+ width: 2rem; height: 2rem; border-radius: 0.55rem; flex: none;
81
+ display: flex; align-items: center; justify-content: center;
82
+ background: var(--dm-purple-50); color: var(--dm-purple);
83
+ }
84
+ .panel-icon svg { width: 1.05rem; height: 1.05rem; }
85
+ .panel h2 { font-size: 0.98rem; font-weight: 700; margin: 0; }
86
+ .panel .desc { font-size: 0.83rem; color: var(--dm-ink-soft); margin: 0 0 0.75rem; }
87
+
88
+ .code {
89
+ background: var(--dm-code-bg); color: var(--dm-code-ink);
90
+ border-radius: 0.55rem; padding: 0.65rem 0.75rem; margin: 0 0 0.75rem;
91
+ font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
92
+ font-size: 0.78rem; line-height: 1.5; white-space: pre; overflow-x: auto;
93
+ }
94
+
95
+ .controls { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.6rem; }
96
+
97
+ .btn {
98
+ background: linear-gradient(135deg, var(--dm-purple), var(--dm-purple-dark));
99
+ color: #fff; border: none; border-radius: 0.5rem;
100
+ padding: 0.45rem 0.9rem; font-size: 0.82rem; font-weight: 600; cursor: pointer;
101
+ }
102
+ .btn:hover { filter: brightness(1.05); }
103
+ .btn:disabled { opacity: 0.5; cursor: default; filter: none; }
104
+ .btn.secondary {
105
+ background: #fff; color: var(--dm-purple-dark);
106
+ border: 1px solid var(--dm-border);
107
+ }
108
+ .btn.secondary:hover { background: var(--dm-purple-50); }
109
+
110
+ input.text {
111
+ border: 1px solid var(--dm-border); border-radius: 0.5rem;
112
+ padding: 0.4rem 0.6rem; font-size: 0.82rem; min-width: 0; flex: 1;
113
+ }
114
+ input.text:focus { outline: 2px solid var(--dm-purple-light); border-color: var(--dm-purple); }
115
+
116
+ .result {
117
+ margin-top: auto; font-size: 0.82rem; border-radius: 0.55rem;
118
+ padding: 0.6rem 0.7rem; background: var(--dm-ok-bg);
119
+ border: 1px solid var(--dm-ok-border); color: #065f46;
120
+ white-space: pre-wrap; word-break: break-word; max-height: 180px; overflow: auto;
121
+ }
122
+ .result.err { background: var(--dm-err-bg); border-color: var(--dm-err-border); color: var(--dm-err); }
123
+ .result.hint { background: var(--dm-purple-50); border-color: var(--dm-purple-100); color: #6b21a8; }
124
+
125
+ .kv { display: grid; grid-template-columns: max-content 1fr; gap: 0.2rem 0.9rem; font-size: 0.83rem; }
126
+ .kv dt { color: var(--dm-ink-soft); }
127
+ .kv dd { margin: 0; font-weight: 500; word-break: break-word; }
128
+
129
+ ul.rows { list-style: none; padding: 0; margin: 0.25rem 0 0; font-size: 0.82rem; }
130
+ ul.rows li { padding: 0.3rem 0; border-bottom: 1px solid var(--dm-border-soft); }
131
+ ul.rows li:last-child { border-bottom: none; }
132
+
133
+ .footer { margin-top: 2rem; text-align: center; font-size: 0.78rem; color: var(--dm-ink-faint); }
134
+ .footer a { color: var(--dm-purple); text-decoration: none; }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "jsx": "preserve",
10
+ "skipLibCheck": true,
11
+ "esModuleInterop": true,
12
+ "isolatedModules": true,
13
+ "verbatimModuleSyntax": true,
14
+ "types": []
15
+ },
16
+ "include": ["src", "env.d.ts"]
17
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vite';
2
+ import vue from '@vitejs/plugin-vue';
3
+
4
+ // base './' is required: published bundles are served under a signed token
5
+ // path prefix, so every asset URL must stay relative.
6
+ export default defineConfig({
7
+ base: './',
8
+ plugins: [vue()],
9
+ });
@@ -0,0 +1,37 @@
1
+ # __APP_NAME__
2
+
3
+ A minimal DataMagik SPA app (Vue 3 + Vite + `@datamagik/app-sdk`). It connects
4
+ to the platform, shows the app context, and runs one lookup-table query.
5
+
6
+ ## Get started
7
+
8
+ ```bash
9
+ npm install
10
+ # set "appId" in dm.config.json to your application id (App Studio header)
11
+ npx dm login --url https://staging.data-magik.com # or https://data-magik.com
12
+ npx dm dev # run it now — uses the bundled demo types
13
+ ```
14
+
15
+ ## Add real resources
16
+
17
+ The starter ships a placeholder `parts` lookup table. Replace it with your own:
18
+
19
+ ```bash
20
+ npx dm add lookup_table # search the tenant, pick one, name an alias
21
+ # remove the placeholder `parts` entry from dm.config.json, then:
22
+ npx dm typegen # refresh the typed surface (src/dm.generated.ts)
23
+ ```
24
+
25
+ `dm add` also handles ODBC queries, scripts, serial series, and printers.
26
+
27
+ ## Ship it
28
+
29
+ ```bash
30
+ npx dm publish --message "first version" # builds and goes live immediately
31
+ ```
32
+
33
+ ## Files
34
+
35
+ - `dm.config.json` — your app id + declared resources (commit it).
36
+ - `src/dm.generated.ts` — typed alias surface, regenerated by `dm typegen` (commit it).
37
+ - `src/App.vue` — the app.
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ *.local
4
+ .DS_Store
@@ -0,0 +1,10 @@
1
+ {
2
+ "appId": __APP_ID__,
3
+ "entry": "index.html",
4
+ "sources": [
5
+ { "sourceId": 1, "type": "lookup_table", "alias": "parts" }
6
+ ],
7
+ "serialSeries": [],
8
+ "printers": [],
9
+ "appContract": { "inputs": [], "outputs": [], "events": [] }
10
+ }
@@ -0,0 +1,7 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import type { DefineComponent } from 'vue';
5
+ const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
6
+ export default component;
7
+ }
@@ -0,0 +1,12 @@
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.0" />
6
+ <title>__APP_NAME__ — DataMagik</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "__PKG_NAME__",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "dm dev",
8
+ "build": "vue-tsc --noEmit -p tsconfig.json && vite build",
9
+ "typecheck": "vue-tsc --noEmit -p tsconfig.json",
10
+ "preview": "vite preview",
11
+ "typegen": "dm typegen",
12
+ "deploy": "dm publish"
13
+ },
14
+ "dependencies": {
15
+ "@datamagik/app-sdk": "^0.1.0",
16
+ "vue": "^3.5.13"
17
+ },
18
+ "devDependencies": {
19
+ "@datamagik/cli": "^0.1.0",
20
+ "@vitejs/plugin-vue": "^5.2.0",
21
+ "typescript": "^5.6.0",
22
+ "vite": "^6.3.5",
23
+ "vue-tsc": "^2.2.0"
24
+ }
25
+ }
@@ -0,0 +1,71 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, ref } from 'vue';
3
+ import { DmError } from '@datamagik/app-sdk';
4
+ import type { DmContext } from '@datamagik/app-sdk';
5
+ import { dm } from './dm.generated';
6
+ import type { PartsRow } from './dm.generated';
7
+
8
+ const status = ref<'connecting' | 'ok' | 'error'>('connecting');
9
+ const ctx = ref<DmContext | null>(null);
10
+ const rows = ref<PartsRow[]>([]);
11
+ const dataError = ref('');
12
+ const fatal = ref('');
13
+
14
+ onMounted(async () => {
15
+ try {
16
+ ctx.value = await dm.init();
17
+ status.value = 'ok';
18
+ } catch (e) {
19
+ status.value = 'error';
20
+ fatal.value = e instanceof DmError ? `${e.code}: ${e.message}` : String(e);
21
+ return;
22
+ }
23
+ try {
24
+ const result = await dm.data.query('parts', { pageSize: 25 });
25
+ rows.value = result.rows;
26
+ } catch (e) {
27
+ // The starter declares a placeholder `parts` id. Wire a real lookup table
28
+ // with `dm add lookup_table` (then `dm typegen`) to see live data here.
29
+ dataError.value = e instanceof DmError ? `${e.code}: ${e.message}` : String(e);
30
+ }
31
+ });
32
+
33
+ function rowText(row: PartsRow): string {
34
+ return typeof row.display_text === 'string' ? row.display_text : JSON.stringify(row);
35
+ }
36
+ </script>
37
+
38
+ <template>
39
+ <header>
40
+ <span class="dot" :class="{ ok: status === 'ok', err: status === 'error' }"></span>
41
+ <h1>{{ ctx?.appName || '__APP_NAME__' }}</h1>
42
+ </header>
43
+
44
+ <div class="card">
45
+ <h2>Connection</h2>
46
+ <p v-if="status === 'connecting'" class="muted">Connecting to the platform…</p>
47
+ <dl v-else-if="ctx" class="kv">
48
+ <dt>App</dt>
49
+ <dd>{{ ctx.appName }} (v{{ ctx.version }})</dd>
50
+ <dt>Surface</dt>
51
+ <dd>{{ ctx.surface }}</dd>
52
+ <dt>User</dt>
53
+ <dd>{{ ctx.user.name }}</dd>
54
+ <dt>Company</dt>
55
+ <dd>{{ ctx.company.name }}</dd>
56
+ </dl>
57
+ <p v-else class="error">{{ fatal }}</p>
58
+ </div>
59
+
60
+ <div class="card">
61
+ <h2><code>parts</code> — lookup table query</h2>
62
+ <ul v-if="rows.length" class="rows">
63
+ <li v-for="(row, i) in rows" :key="i">{{ rowText(row) }}</li>
64
+ </ul>
65
+ <p v-else-if="dataError" class="error">
66
+ No data yet — {{ dataError }}.<br />
67
+ Declare a real lookup table with <code>dm add lookup_table</code>, then run <code>dm typegen</code>.
68
+ </p>
69
+ <p v-else class="muted">No rows returned.</p>
70
+ </div>
71
+ </template>
@@ -0,0 +1,32 @@
1
+ /* eslint-disable */
2
+ // ----------------------------------------------------------------------------
3
+ // Generated by `dm typegen` — DO NOT EDIT.
4
+ // This is a starter STUB so the project type-checks before you connect. Set a
5
+ // real "appId" + resource ids in dm.config.json and run `dm typegen`; that
6
+ // overwrites this file with types fetched from your tenant.
7
+ // ----------------------------------------------------------------------------
8
+ import { createDm } from '@datamagik/app-sdk';
9
+ import type { AliasRegistry } from '@datamagik/app-sdk';
10
+
11
+ /** Row of the `parts` lookup table (replaced by real columns on `dm typegen`). */
12
+ export interface PartsRow {
13
+ display_text: string;
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ /** Typed alias surface for this app (the generic of `createDm`). */
18
+ export interface DmGenerated {
19
+ tables: { parts: PartsRow };
20
+ odbc: {};
21
+ scripts: {};
22
+ serials: {};
23
+ printers: {};
24
+ }
25
+
26
+ /** Runtime alias → { type, id } registry. */
27
+ export const dmRegistry: AliasRegistry = {
28
+ parts: { type: 'lookup_table', id: 1 },
29
+ };
30
+
31
+ /** Ready-to-use, fully typed SDK instance for this app. */
32
+ export const dm = createDm<DmGenerated>(dmRegistry);
@@ -0,0 +1,5 @@
1
+ import { createApp } from 'vue';
2
+ import App from './App.vue';
3
+ import './style.css';
4
+
5
+ createApp(App).mount('#app');
@@ -0,0 +1,63 @@
1
+ :root {
2
+ --dm-purple: #9333ea;
3
+ --dm-purple-dark: #7e22ce;
4
+ --dm-bg: #f9fafb;
5
+ --dm-card: #ffffff;
6
+ --dm-border: #e5e7eb;
7
+ --dm-ink: #111827;
8
+ --dm-ink-soft: #6b7280;
9
+ --dm-err: #dc2626;
10
+ --dm-err-bg: #fef2f2;
11
+
12
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
13
+ color: var(--dm-ink);
14
+ }
15
+
16
+ * { box-sizing: border-box; }
17
+ body { margin: 0; background: var(--dm-bg); }
18
+
19
+ #app { max-width: 720px; margin: 0 auto; padding: 2rem 1rem; }
20
+
21
+ header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.5rem; }
22
+ header h1 { font-size: 1.5rem; font-weight: 700; margin: 0; }
23
+
24
+ .dot {
25
+ width: 0.6rem; height: 0.6rem; border-radius: 50%;
26
+ background: var(--dm-ink-soft); flex: none;
27
+ }
28
+ .dot.ok { background: #059669; }
29
+ .dot.err { background: var(--dm-err); }
30
+
31
+ .card {
32
+ background: var(--dm-card);
33
+ border: 1px solid var(--dm-border);
34
+ border-radius: 0.75rem;
35
+ padding: 1.25rem;
36
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
37
+ margin-bottom: 1rem;
38
+ }
39
+ .card h2 { font-size: 1rem; margin: 0 0 0.75rem; }
40
+
41
+ .muted { color: var(--dm-ink-soft); font-size: 0.875rem; }
42
+
43
+ .kv { display: grid; grid-template-columns: max-content 1fr; gap: 0.25rem 1rem; font-size: 0.9rem; }
44
+ .kv dt { color: var(--dm-ink-soft); }
45
+ .kv dd { margin: 0; font-weight: 500; }
46
+
47
+ ul.rows { list-style: none; padding: 0; margin: 0; }
48
+ ul.rows li { padding: 0.4rem 0; border-bottom: 1px solid var(--dm-border); font-size: 0.9rem; }
49
+ ul.rows li:last-child { border-bottom: none; }
50
+
51
+ .error {
52
+ background: var(--dm-err-bg); border: 1px solid #fecaca;
53
+ color: var(--dm-err); border-radius: 0.5rem; padding: 0.75rem;
54
+ font-size: 0.85rem;
55
+ }
56
+
57
+ button {
58
+ background: var(--dm-purple); color: #fff; border: none;
59
+ border-radius: 0.5rem; padding: 0.5rem 1rem; font-size: 0.875rem;
60
+ font-weight: 600; cursor: pointer;
61
+ }
62
+ button:hover { background: var(--dm-purple-dark); }
63
+ button:disabled { opacity: 0.5; cursor: default; }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "jsx": "preserve",
10
+ "skipLibCheck": true,
11
+ "esModuleInterop": true,
12
+ "isolatedModules": true,
13
+ "verbatimModuleSyntax": true,
14
+ "types": []
15
+ },
16
+ "include": ["src", "env.d.ts"]
17
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vite';
2
+ import vue from '@vitejs/plugin-vue';
3
+
4
+ // base './' is required: published bundles are served under a signed token
5
+ // path prefix, so every asset URL must stay relative.
6
+ export default defineConfig({
7
+ base: './',
8
+ plugins: [vue()],
9
+ });