orizu 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "orizu",
3
+ "version": "0.0.2",
4
+ "private": false,
5
+ "type": "module",
6
+ "bin": {
7
+ "orizu": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -p tsconfig.json"
11
+ }
12
+ }
@@ -0,0 +1,37 @@
1
+ import { mkdirSync, readFileSync, rmSync, writeFileSync, chmodSync, existsSync } from 'fs'
2
+ import { join } from 'path'
3
+ import { homedir } from 'os'
4
+ import { StoredCredentials } from './types.js'
5
+
6
+ function getConfigDir(): string {
7
+ return join(homedir(), '.config', 'orizu')
8
+ }
9
+
10
+ function getCredentialsPath(): string {
11
+ return join(getConfigDir(), 'credentials.json')
12
+ }
13
+
14
+ export function saveCredentials(credentials: StoredCredentials) {
15
+ const dir = getConfigDir()
16
+ mkdirSync(dir, { recursive: true })
17
+ const path = getCredentialsPath()
18
+ writeFileSync(path, JSON.stringify(credentials, null, 2), 'utf-8')
19
+ chmodSync(path, 0o600)
20
+ }
21
+
22
+ export function loadCredentials(): StoredCredentials | null {
23
+ const path = getCredentialsPath()
24
+ if (!existsSync(path)) {
25
+ return null
26
+ }
27
+
28
+ const raw = readFileSync(path, 'utf-8')
29
+ return JSON.parse(raw) as StoredCredentials
30
+ }
31
+
32
+ export function clearCredentials() {
33
+ const path = getCredentialsPath()
34
+ if (existsSync(path)) {
35
+ rmSync(path)
36
+ }
37
+ }
package/src/csv.ts ADDED
@@ -0,0 +1,83 @@
1
+ export function parseCSV(csvText: string): string[][] {
2
+ const result: string[][] = []
3
+ let currentRow: string[] = []
4
+ let currentField = ''
5
+ let inQuotes = false
6
+ let i = 0
7
+
8
+ while (i < csvText.length) {
9
+ const char = csvText[i]
10
+ const nextChar = csvText[i + 1]
11
+
12
+ if (char === '"') {
13
+ if (inQuotes && nextChar === '"') {
14
+ currentField += '"'
15
+ i += 2
16
+ continue
17
+ }
18
+
19
+ inQuotes = !inQuotes
20
+ i++
21
+ continue
22
+ }
23
+
24
+ if (!inQuotes) {
25
+ if (char === ',') {
26
+ currentRow.push(currentField)
27
+ currentField = ''
28
+ i++
29
+ continue
30
+ }
31
+
32
+ if (char === '\n' || char === '\r') {
33
+ if (currentField || currentRow.length > 0) {
34
+ currentRow.push(currentField)
35
+ if (currentRow.some(field => field.trim())) {
36
+ result.push(currentRow)
37
+ }
38
+ currentRow = []
39
+ currentField = ''
40
+ }
41
+
42
+ if (char === '\r' && nextChar === '\n') {
43
+ i += 2
44
+ } else {
45
+ i++
46
+ }
47
+
48
+ continue
49
+ }
50
+ }
51
+
52
+ currentField += char
53
+ i++
54
+ }
55
+
56
+ if (currentField || currentRow.length > 0) {
57
+ currentRow.push(currentField)
58
+ if (currentRow.some(field => field.trim())) {
59
+ result.push(currentRow)
60
+ }
61
+ }
62
+
63
+ return result
64
+ }
65
+
66
+ export function parseCSVToObjects(csvText: string): Record<string, unknown>[] {
67
+ const rows = parseCSV(csvText)
68
+
69
+ if (rows.length < 2) {
70
+ return []
71
+ }
72
+
73
+ const headers = rows[0].map(header => header.trim())
74
+ const dataRows = rows.slice(1)
75
+
76
+ return dataRows.map(row => {
77
+ const obj: Record<string, unknown> = {}
78
+ headers.forEach((header, index) => {
79
+ obj[header] = row[index]?.trim() || ''
80
+ })
81
+ return obj
82
+ })
83
+ }
@@ -0,0 +1,83 @@
1
+ import { readFileSync } from 'fs'
2
+ import { extname } from 'path'
3
+ import { parseCSVToObjects } from './csv.js'
4
+
5
+ export function parseDatasetFile(filePath: string): {
6
+ rows: Array<Record<string, unknown>>
7
+ sourceType: 'csv' | 'json' | 'jsonl'
8
+ } {
9
+ const extension = extname(filePath).toLowerCase()
10
+ let content: string
11
+
12
+ try {
13
+ content = readFileSync(filePath, 'utf-8')
14
+ } catch (error) {
15
+ const maybeError = error as NodeJS.ErrnoException
16
+
17
+ if (maybeError.code === 'ENOENT') {
18
+ throw new Error(
19
+ `File not found: ${filePath}. Check the path and filename, then retry.`
20
+ )
21
+ }
22
+
23
+ if (maybeError.code === 'EPERM' || maybeError.code === 'EACCES') {
24
+ throw new Error(
25
+ `Cannot read file: ${filePath}. macOS may be blocking access to this folder (for example Downloads). Grant folder permission to your terminal app and retry.`
26
+ )
27
+ }
28
+
29
+ throw new Error(`Failed to read file ${filePath}: ${maybeError.message}`)
30
+ }
31
+
32
+ if (extension === '.csv') {
33
+ const rows = parseCSVToObjects(content)
34
+ return {
35
+ rows: ensureObjectRows(rows),
36
+ sourceType: 'csv',
37
+ }
38
+ }
39
+
40
+ if (extension === '.json') {
41
+ const data = JSON.parse(content)
42
+ if (!Array.isArray(data)) {
43
+ throw new Error('JSON file must contain a top-level array')
44
+ }
45
+
46
+ return {
47
+ rows: ensureObjectRows(data),
48
+ sourceType: 'json',
49
+ }
50
+ }
51
+
52
+ if (extension === '.jsonl') {
53
+ const lines = content.split(/\r?\n/).map(line => line.trim()).filter(Boolean)
54
+ const parsed = lines.map((line, index) => {
55
+ try {
56
+ return JSON.parse(line)
57
+ } catch {
58
+ throw new Error(`Invalid JSONL at line ${index + 1}`)
59
+ }
60
+ })
61
+
62
+ return {
63
+ rows: ensureObjectRows(parsed),
64
+ sourceType: 'jsonl',
65
+ }
66
+ }
67
+
68
+ throw new Error('Unsupported file type. Use .csv, .json, or .jsonl')
69
+ }
70
+
71
+ function ensureObjectRows(rows: unknown[]): Array<Record<string, unknown>> {
72
+ if (rows.length === 0) {
73
+ throw new Error('Dataset file contains no rows')
74
+ }
75
+
76
+ return rows.map((row, index) => {
77
+ if (!row || Array.isArray(row) || typeof row !== 'object') {
78
+ throw new Error(`Row ${index + 1} must be a JSON object`)
79
+ }
80
+
81
+ return row as Record<string, unknown>
82
+ })
83
+ }
package/src/http.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { loadCredentials, saveCredentials } from './credentials.js'
2
+ import { LoginResponse, StoredCredentials } from './types.js'
3
+
4
+ export function getBaseUrl(): string {
5
+ return process.env.ORIZU_BASE_URL || 'http://localhost:3000'
6
+ }
7
+
8
+ function isExpired(expiresAt: number): boolean {
9
+ const nowUnix = Math.floor(Date.now() / 1000)
10
+ return expiresAt <= nowUnix + 30
11
+ }
12
+
13
+ async function refreshCredentials(credentials: StoredCredentials): Promise<StoredCredentials> {
14
+ const response = await fetch(`${credentials.baseUrl}/api/cli/auth/refresh`, {
15
+ method: 'POST',
16
+ headers: { 'Content-Type': 'application/json' },
17
+ body: JSON.stringify({ refreshToken: credentials.refreshToken }),
18
+ })
19
+
20
+ if (!response.ok) {
21
+ throw new Error('Session expired. Run `orizu login` again.')
22
+ }
23
+
24
+ const data = await response.json() as LoginResponse
25
+ const refreshed = {
26
+ accessToken: data.accessToken,
27
+ refreshToken: data.refreshToken,
28
+ expiresAt: data.expiresAt,
29
+ baseUrl: credentials.baseUrl,
30
+ }
31
+ saveCredentials(refreshed)
32
+ return refreshed
33
+ }
34
+
35
+ export async function authedFetch(path: string, init: RequestInit = {}) {
36
+ const credentials = loadCredentials()
37
+ if (!credentials) {
38
+ throw new Error('Not logged in. Run `orizu login` first.')
39
+ }
40
+
41
+ let activeCredentials = credentials
42
+ if (isExpired(activeCredentials.expiresAt)) {
43
+ activeCredentials = await refreshCredentials(activeCredentials)
44
+ }
45
+
46
+ let response = await fetch(`${activeCredentials.baseUrl}${path}`, {
47
+ ...init,
48
+ headers: {
49
+ ...(init.headers || {}),
50
+ Authorization: `Bearer ${activeCredentials.accessToken}`,
51
+ },
52
+ })
53
+
54
+ if (response.status === 401) {
55
+ activeCredentials = await refreshCredentials(activeCredentials)
56
+ response = await fetch(`${activeCredentials.baseUrl}${path}`, {
57
+ ...init,
58
+ headers: {
59
+ ...(init.headers || {}),
60
+ Authorization: `Bearer ${activeCredentials.accessToken}`,
61
+ },
62
+ })
63
+ }
64
+
65
+ return response
66
+ }