iii-sdk 0.2.0 → 0.2.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 (36) hide show
  1. package/dist/{iii-7FpY7bi9.d.mts → iii-CAEmlG6f.d.mts} +18 -5
  2. package/dist/iii-CAEmlG6f.d.mts.map +1 -0
  3. package/dist/{iii-BhtLRYBs.d.cts → iii-DEbgvZtB.d.cts} +15 -2
  4. package/dist/iii-DEbgvZtB.d.cts.map +1 -0
  5. package/dist/index.cjs +9 -7
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +1 -1
  8. package/dist/index.d.mts +1 -1
  9. package/dist/index.mjs +9 -7
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/{otel-worker-gauges-Dka1CFDy.mjs → otel-worker-gauges-CHooGOLC.mjs} +144 -12
  12. package/dist/otel-worker-gauges-CHooGOLC.mjs.map +1 -0
  13. package/dist/{otel-worker-gauges-8AUNGQgJ.cjs → otel-worker-gauges-CLZyxI1P.cjs} +137 -5
  14. package/dist/otel-worker-gauges-CLZyxI1P.cjs.map +1 -0
  15. package/dist/stream-Bzpo5JNV.d.mts.map +1 -1
  16. package/dist/telemetry.cjs +1 -1
  17. package/dist/telemetry.d.cts +1 -1
  18. package/dist/telemetry.d.mts +1 -1
  19. package/dist/telemetry.mjs +1 -1
  20. package/package.json +1 -1
  21. package/tests/api-triggers.test.ts +163 -0
  22. package/tests/bridge.test.ts +84 -0
  23. package/tests/exports.test.ts +37 -0
  24. package/tests/fetch-instrumentation.test.ts +623 -0
  25. package/tests/fixtures/config-test.yaml +66 -0
  26. package/tests/healthcheck.test.ts +1 -2
  27. package/tests/kv-server.test.ts +82 -0
  28. package/tests/pubsub.test.ts +117 -0
  29. package/tests/setup.ts +2 -32
  30. package/tests/state.test.ts +1 -2
  31. package/tests/stream.test.ts +1 -2
  32. package/tests/utils.ts +2 -23
  33. package/dist/iii-7FpY7bi9.d.mts.map +0 -1
  34. package/dist/iii-BhtLRYBs.d.cts.map +0 -1
  35. package/dist/otel-worker-gauges-8AUNGQgJ.cjs.map +0 -1
  36. package/dist/otel-worker-gauges-Dka1CFDy.mjs.map +0 -1
@@ -0,0 +1,163 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import type { ApiRequest, ApiResponse } from '../src'
3
+ import { execute, httpRequest, iii, sleep } from './utils'
4
+
5
+ describe('API Triggers', () => {
6
+ it('should register GET endpoint', async () => {
7
+ const fn = iii.registerFunction(
8
+ { id: 'test.api.get' },
9
+ async (_req: ApiRequest): Promise<ApiResponse> => ({
10
+ status_code: 200,
11
+ body: { message: 'Hello from GET' },
12
+ }),
13
+ )
14
+
15
+ const trigger = iii.registerTrigger({
16
+ type: 'http',
17
+ function_id: fn.id,
18
+ config: {
19
+ api_path: 'test/hello',
20
+ http_method: 'GET',
21
+ },
22
+ })
23
+
24
+ await sleep(300)
25
+
26
+ const response = await execute(async () => httpRequest('GET', '/test/hello'))
27
+
28
+ expect(response.status).toBe(200)
29
+ expect(response.data).toEqual({ message: 'Hello from GET' })
30
+
31
+ fn.unregister()
32
+ trigger.unregister()
33
+ })
34
+
35
+ it('should register POST endpoint with body', async () => {
36
+ const fn = iii.registerFunction(
37
+ { id: 'test.api.post' },
38
+ async (req: ApiRequest): Promise<ApiResponse> => {
39
+ const body = (req.body as Record<string, unknown>) ?? {}
40
+ return {
41
+ status_code: 201,
42
+ body: { received: body, created: true },
43
+ }
44
+ },
45
+ )
46
+
47
+ const trigger = iii.registerTrigger({
48
+ type: 'http',
49
+ function_id: fn.id,
50
+ config: {
51
+ api_path: 'test/items',
52
+ http_method: 'POST',
53
+ },
54
+ })
55
+
56
+ await sleep(300)
57
+
58
+ const response = await execute(async () =>
59
+ httpRequest('POST', '/test/items', { name: 'test item', value: 123 }),
60
+ )
61
+
62
+ expect(response.status).toBe(201)
63
+ expect(response.data.created).toBe(true)
64
+ expect(response.data.received).toHaveProperty('name', 'test item')
65
+
66
+ fn.unregister()
67
+ trigger.unregister()
68
+ })
69
+
70
+ it('should handle path parameters', async () => {
71
+ const fn = iii.registerFunction(
72
+ { id: 'test.api.getById' },
73
+ async (req: ApiRequest): Promise<ApiResponse> => ({
74
+ status_code: 200,
75
+ body: { id: req.path_params?.id },
76
+ }),
77
+ )
78
+
79
+ const trigger = iii.registerTrigger({
80
+ type: 'http',
81
+ function_id: fn.id,
82
+ config: {
83
+ api_path: 'test/items/:id',
84
+ http_method: 'GET',
85
+ },
86
+ })
87
+
88
+ await sleep(300)
89
+
90
+ const response = await execute(async () => httpRequest('GET', '/test/items/abc123'))
91
+
92
+ expect(response.status).toBe(200)
93
+ expect(response.data).toEqual({ id: 'abc123' })
94
+
95
+ fn.unregister()
96
+ trigger.unregister()
97
+ })
98
+
99
+ it('should handle query parameters', async () => {
100
+ const fn = iii.registerFunction(
101
+ { id: 'test.api.search' },
102
+ async (req: ApiRequest): Promise<ApiResponse> => {
103
+ const q = req.query_params?.q
104
+ const limit = req.query_params?.limit
105
+ const qVal = Array.isArray(q) ? q[0] : q
106
+ const limitVal = Array.isArray(limit) ? limit[0] : limit
107
+ return {
108
+ status_code: 200,
109
+ body: { query: qVal, limit: limitVal },
110
+ }
111
+ },
112
+ )
113
+
114
+ const trigger = iii.registerTrigger({
115
+ type: 'http',
116
+ function_id: fn.id,
117
+ config: {
118
+ api_path: 'test/search',
119
+ http_method: 'GET',
120
+ },
121
+ })
122
+
123
+ await sleep(300)
124
+
125
+ const response = await execute(async () => httpRequest('GET', '/test/search?q=hello&limit=10'))
126
+
127
+ expect(response.status).toBe(200)
128
+ expect(response.data.query).toBe('hello')
129
+ expect(response.data.limit).toBe('10')
130
+
131
+ fn.unregister()
132
+ trigger.unregister()
133
+ })
134
+
135
+ it('should return custom status code', async () => {
136
+ const fn = iii.registerFunction(
137
+ { id: 'test.api.notfound' },
138
+ async (_req: ApiRequest): Promise<ApiResponse<404>> => ({
139
+ status_code: 404,
140
+ body: { error: 'Not found' },
141
+ }),
142
+ )
143
+
144
+ const trigger = iii.registerTrigger({
145
+ type: 'http',
146
+ function_id: fn.id,
147
+ config: {
148
+ api_path: 'test/missing',
149
+ http_method: 'GET',
150
+ },
151
+ })
152
+
153
+ await sleep(300)
154
+
155
+ const response = await execute(async () => httpRequest('GET', '/test/missing'))
156
+
157
+ expect(response.status).toBe(404)
158
+ expect(response.data).toEqual({ error: 'Not found' })
159
+
160
+ fn.unregister()
161
+ trigger.unregister()
162
+ })
163
+ })
@@ -0,0 +1,84 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { execute, iii, sleep } from './utils'
3
+
4
+ describe('Bridge Operations', () => {
5
+ it('should connect successfully', async () => {
6
+ expect(iii).toBeDefined()
7
+ const functions = await execute(async () => iii.listFunctions())
8
+ expect(Array.isArray(functions)).toBe(true)
9
+ })
10
+
11
+ it('should register and invoke a function', async () => {
12
+ let receivedData: Record<string, unknown> | undefined
13
+
14
+ const fn = iii.registerFunction({ id: 'test.echo' }, async (data: Record<string, unknown>) => {
15
+ receivedData = data
16
+ return { echoed: data }
17
+ })
18
+
19
+ await sleep(300)
20
+
21
+ const result = await iii.call<Record<string, unknown>, { echoed: Record<string, unknown> }>(
22
+ 'test.echo',
23
+ { message: 'hello' },
24
+ )
25
+
26
+ expect(result).toHaveProperty('echoed')
27
+ expect(result.echoed).toHaveProperty('message', 'hello')
28
+ expect(receivedData).toHaveProperty('message', 'hello')
29
+
30
+ fn.unregister()
31
+ })
32
+
33
+ it('should invoke function fire-and-forget', async () => {
34
+ let receivedData: Record<string, unknown> | undefined
35
+ let resolveReceived: () => void
36
+ const received = new Promise<void>(r => {
37
+ resolveReceived = r
38
+ })
39
+
40
+ const fn = iii.registerFunction(
41
+ { id: 'test.receiver' },
42
+ async (data: Record<string, unknown>) => {
43
+ receivedData = data
44
+ resolveReceived?.()
45
+ return {}
46
+ },
47
+ )
48
+
49
+ await sleep(300)
50
+
51
+ iii.callVoid('test.receiver', { value: 42 })
52
+
53
+ await Promise.race([
54
+ received,
55
+ new Promise<never>((_, reject) =>
56
+ setTimeout(() => reject(new Error('Timeout waiting for fire-and-forget')), 5000),
57
+ ),
58
+ ])
59
+
60
+ expect(receivedData).toHaveProperty('value', 42)
61
+
62
+ fn.unregister()
63
+ })
64
+
65
+ it('should list registered functions', async () => {
66
+ const fn1 = iii.registerFunction({ id: 'test.list.func1' }, async () => ({}))
67
+ const fn2 = iii.registerFunction({ id: 'test.list.func2' }, async () => ({}))
68
+
69
+ await sleep(300)
70
+
71
+ const functions = await iii.listFunctions()
72
+ const functionIds = functions.map(f => f.function_id)
73
+
74
+ expect(functionIds).toContain('test.list.func1')
75
+ expect(functionIds).toContain('test.list.func2')
76
+
77
+ fn1.unregister()
78
+ fn2.unregister()
79
+ })
80
+
81
+ it('should reject when invoking non-existent function', async () => {
82
+ await expect(iii.call('nonexistent.function', {}, 2000)).rejects.toThrow()
83
+ })
84
+ })
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { init, getContext, withContext, Logger } from '../src/index'
3
+ import { initOtel, shutdownOtel, getTracer, getMeter, getLogger } from '../src/telemetry'
4
+
5
+ describe('Package Exports', () => {
6
+ it('should export main SDK symbols', () => {
7
+ expect(init).toBeDefined()
8
+ expect(typeof init).toBe('function')
9
+ expect(getContext).toBeDefined()
10
+ expect(withContext).toBeDefined()
11
+ expect(Logger).toBeDefined()
12
+ })
13
+
14
+ it('should import stream module', async () => {
15
+ await expect(import('../src/stream')).resolves.toBeDefined()
16
+ })
17
+
18
+ it('should import state module', async () => {
19
+ const stateModule = await import('../src/state')
20
+ expect(stateModule).toBeDefined()
21
+ expect(stateModule.StateEventType).toBeDefined()
22
+ expect(Object.keys(stateModule).length).toBeGreaterThan(0)
23
+ })
24
+
25
+ it('should export telemetry utilities', () => {
26
+ expect(initOtel).toBeDefined()
27
+ expect(typeof initOtel).toBe('function')
28
+ expect(shutdownOtel).toBeDefined()
29
+ expect(typeof shutdownOtel).toBe('function')
30
+ expect(getTracer).toBeDefined()
31
+ expect(typeof getTracer).toBe('function')
32
+ expect(getMeter).toBeDefined()
33
+ expect(typeof getMeter).toBe('function')
34
+ expect(getLogger).toBeDefined()
35
+ expect(typeof getLogger).toBe('function')
36
+ })
37
+ })