@astrale-os/sdk 0.4.11 → 0.4.13

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 (331) hide show
  1. package/dist/auth/authenticate.d.ts +1 -1
  2. package/dist/auth/authenticate.d.ts.map +1 -1
  3. package/dist/auth/authenticate.js +2 -2
  4. package/dist/auth/authenticate.js.map +1 -1
  5. package/dist/auth/check.js +1 -1
  6. package/dist/auth/check.js.map +1 -1
  7. package/dist/auth/function-context.d.ts +1 -1
  8. package/dist/auth/function-context.d.ts.map +1 -1
  9. package/dist/auth/function-context.js +3 -3
  10. package/dist/auth/function-context.js.map +1 -1
  11. package/dist/auth/index.d.ts +15 -15
  12. package/dist/auth/index.d.ts.map +1 -1
  13. package/dist/auth/index.js +10 -10
  14. package/dist/auth/index.js.map +1 -1
  15. package/dist/auth/issuer-mint.d.ts +1 -1
  16. package/dist/auth/issuer-mint.d.ts.map +1 -1
  17. package/dist/auth/issuer-mint.js +2 -2
  18. package/dist/auth/issuer-mint.js.map +1 -1
  19. package/dist/auth/kernel-client.d.ts +1 -1
  20. package/dist/auth/kernel-client.d.ts.map +1 -1
  21. package/dist/auth/kernel-client.js +2 -2
  22. package/dist/auth/kernel-client.js.map +1 -1
  23. package/dist/auth/resolve.d.ts +2 -2
  24. package/dist/auth/resolve.d.ts.map +1 -1
  25. package/dist/auth/resolve.js +2 -2
  26. package/dist/auth/resolve.js.map +1 -1
  27. package/dist/auth/verify.d.ts +1 -1
  28. package/dist/auth/verify.d.ts.map +1 -1
  29. package/dist/auth/verify.js +2 -2
  30. package/dist/auth/verify.js.map +1 -1
  31. package/dist/cli/bin.js +1 -1
  32. package/dist/cli/bin.js.map +1 -1
  33. package/dist/cli/index.d.ts +2 -2
  34. package/dist/cli/index.d.ts.map +1 -1
  35. package/dist/cli/index.js +2 -2
  36. package/dist/cli/index.js.map +1 -1
  37. package/dist/cli/publish.js +1 -1
  38. package/dist/cli/publish.js.map +1 -1
  39. package/dist/cli/run.d.ts +9 -3
  40. package/dist/cli/run.d.ts.map +1 -1
  41. package/dist/cli/run.js +55 -5
  42. package/dist/cli/run.js.map +1 -1
  43. package/dist/cli/spec.d.ts +1 -1
  44. package/dist/cli/spec.d.ts.map +1 -1
  45. package/dist/cli/spec.js +1 -1
  46. package/dist/cli/spec.js.map +1 -1
  47. package/dist/config/define-domain.d.ts +2 -2
  48. package/dist/config/define-domain.d.ts.map +1 -1
  49. package/dist/config/deploy.d.ts +2 -2
  50. package/dist/config/deploy.d.ts.map +1 -1
  51. package/dist/config/index.d.ts +6 -6
  52. package/dist/config/index.d.ts.map +1 -1
  53. package/dist/config/index.js +3 -3
  54. package/dist/config/index.js.map +1 -1
  55. package/dist/define/index.d.ts +4 -4
  56. package/dist/define/index.d.ts.map +1 -1
  57. package/dist/define/index.js +2 -2
  58. package/dist/define/index.js.map +1 -1
  59. package/dist/define/remote-function.d.ts +7 -5
  60. package/dist/define/remote-function.d.ts.map +1 -1
  61. package/dist/define/remote-function.js.map +1 -1
  62. package/dist/define/view.d.ts +3 -3
  63. package/dist/define/view.d.ts.map +1 -1
  64. package/dist/deploy/check.d.ts +1 -1
  65. package/dist/deploy/check.d.ts.map +1 -1
  66. package/dist/deploy/check.js +1 -1
  67. package/dist/deploy/check.js.map +1 -1
  68. package/dist/deploy/index.d.ts +2 -2
  69. package/dist/deploy/index.d.ts.map +1 -1
  70. package/dist/deploy/index.js +2 -2
  71. package/dist/deploy/index.js.map +1 -1
  72. package/dist/dispatch/authorize.js +1 -1
  73. package/dist/dispatch/authorize.js.map +1 -1
  74. package/dist/dispatch/dispatcher.d.ts +11 -21
  75. package/dist/dispatch/dispatcher.d.ts.map +1 -1
  76. package/dist/dispatch/dispatcher.js +66 -65
  77. package/dist/dispatch/dispatcher.js.map +1 -1
  78. package/dist/dispatch/execute.d.ts +7 -6
  79. package/dist/dispatch/execute.d.ts.map +1 -1
  80. package/dist/dispatch/execute.js +1 -0
  81. package/dist/dispatch/execute.js.map +1 -1
  82. package/dist/dispatch/identity.d.ts +2 -2
  83. package/dist/dispatch/identity.d.ts.map +1 -1
  84. package/dist/dispatch/index.d.ts +6 -6
  85. package/dist/dispatch/index.d.ts.map +1 -1
  86. package/dist/dispatch/index.js +6 -6
  87. package/dist/dispatch/index.js.map +1 -1
  88. package/dist/dispatch/resolve.d.ts +1 -1
  89. package/dist/dispatch/resolve.d.ts.map +1 -1
  90. package/dist/dispatch/self.d.ts +1 -1
  91. package/dist/dispatch/self.d.ts.map +1 -1
  92. package/dist/domain/build-spec.d.ts +1 -1
  93. package/dist/domain/build-spec.d.ts.map +1 -1
  94. package/dist/domain/build-spec.js +2 -2
  95. package/dist/domain/build-spec.js.map +1 -1
  96. package/dist/domain/contract.d.ts +1 -1
  97. package/dist/domain/contract.d.ts.map +1 -1
  98. package/dist/domain/define.d.ts +4 -4
  99. package/dist/domain/define.d.ts.map +1 -1
  100. package/dist/domain/define.js +2 -2
  101. package/dist/domain/define.js.map +1 -1
  102. package/dist/domain/extend-functions.d.ts +1 -1
  103. package/dist/domain/extend-functions.d.ts.map +1 -1
  104. package/dist/domain/extend-functions.js +1 -1
  105. package/dist/domain/extend-functions.js.map +1 -1
  106. package/dist/domain/extend-views.d.ts +1 -1
  107. package/dist/domain/extend-views.d.ts.map +1 -1
  108. package/dist/domain/extend-views.js +1 -1
  109. package/dist/domain/extend-views.js.map +1 -1
  110. package/dist/domain/index.d.ts +4 -4
  111. package/dist/domain/index.d.ts.map +1 -1
  112. package/dist/domain/index.js +3 -3
  113. package/dist/domain/index.js.map +1 -1
  114. package/dist/index.d.ts +19 -19
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +10 -10
  117. package/dist/index.js.map +1 -1
  118. package/dist/linter/analyze.d.ts +6 -0
  119. package/dist/linter/analyze.d.ts.map +1 -0
  120. package/dist/linter/analyze.js +12 -0
  121. package/dist/linter/analyze.js.map +1 -0
  122. package/dist/linter/diagnostic.d.ts +32 -0
  123. package/dist/linter/diagnostic.d.ts.map +1 -0
  124. package/dist/linter/diagnostic.js +35 -0
  125. package/dist/linter/diagnostic.js.map +1 -0
  126. package/dist/linter/index.d.ts +10 -0
  127. package/dist/linter/index.d.ts.map +1 -0
  128. package/dist/linter/index.js +6 -0
  129. package/dist/linter/index.js.map +1 -0
  130. package/dist/linter/lint.d.ts +8 -0
  131. package/dist/linter/lint.d.ts.map +1 -0
  132. package/dist/linter/lint.js +26 -0
  133. package/dist/linter/lint.js.map +1 -0
  134. package/dist/linter/oxlint/config.d.ts +14 -0
  135. package/dist/linter/oxlint/config.d.ts.map +1 -0
  136. package/dist/linter/oxlint/config.js +18 -0
  137. package/dist/linter/oxlint/config.js.map +1 -0
  138. package/dist/linter/oxlint/plugin.d.ts +13 -0
  139. package/dist/linter/oxlint/plugin.d.ts.map +1 -0
  140. package/dist/linter/oxlint/plugin.js +14 -0
  141. package/dist/linter/oxlint/plugin.js.map +1 -0
  142. package/dist/linter/oxlint/run.d.ts +7 -0
  143. package/dist/linter/oxlint/run.d.ts.map +1 -0
  144. package/dist/linter/oxlint/run.js +122 -0
  145. package/dist/linter/oxlint/run.js.map +1 -0
  146. package/dist/linter/preflight.d.ts +2 -0
  147. package/dist/linter/preflight.d.ts.map +1 -0
  148. package/dist/linter/preflight.js +162 -0
  149. package/dist/linter/preflight.js.map +1 -0
  150. package/dist/linter/project.d.ts +12 -0
  151. package/dist/linter/project.d.ts.map +1 -0
  152. package/dist/linter/project.js +88 -0
  153. package/dist/linter/project.js.map +1 -0
  154. package/dist/linter/report.d.ts +4 -0
  155. package/dist/linter/report.d.ts.map +1 -0
  156. package/dist/linter/report.js +22 -0
  157. package/dist/linter/report.js.map +1 -0
  158. package/dist/linter/rules/catalog.d.ts +56 -0
  159. package/dist/linter/rules/catalog.d.ts.map +1 -0
  160. package/dist/linter/rules/catalog.js +53 -0
  161. package/dist/linter/rules/catalog.js.map +1 -0
  162. package/dist/linter/rules/core-has-no-async.d.ts +3 -0
  163. package/dist/linter/rules/core-has-no-async.d.ts.map +1 -0
  164. package/dist/linter/rules/core-has-no-async.js +43 -0
  165. package/dist/linter/rules/core-has-no-async.js.map +1 -0
  166. package/dist/linter/rules/core-is-pure.d.ts +3 -0
  167. package/dist/linter/rules/core-is-pure.d.ts.map +1 -0
  168. package/dist/linter/rules/core-is-pure.js +74 -0
  169. package/dist/linter/rules/core-is-pure.js.map +1 -0
  170. package/dist/linter/rules/no-nested-steps.d.ts +3 -0
  171. package/dist/linter/rules/no-nested-steps.d.ts.map +1 -0
  172. package/dist/linter/rules/no-nested-steps.js +32 -0
  173. package/dist/linter/rules/no-nested-steps.js.map +1 -0
  174. package/dist/linter/rules/no-read-inside-mutate.d.ts +3 -0
  175. package/dist/linter/rules/no-read-inside-mutate.d.ts.map +1 -0
  176. package/dist/linter/rules/no-read-inside-mutate.js +64 -0
  177. package/dist/linter/rules/no-read-inside-mutate.js.map +1 -0
  178. package/dist/linter/rules/one-remote-definition-per-file.d.ts +3 -0
  179. package/dist/linter/rules/one-remote-definition-per-file.d.ts.map +1 -0
  180. package/dist/linter/rules/one-remote-definition-per-file.js +23 -0
  181. package/dist/linter/rules/one-remote-definition-per-file.js.map +1 -0
  182. package/dist/linter/rules/oxlint-ast.d.ts +30 -0
  183. package/dist/linter/rules/oxlint-ast.d.ts.map +1 -0
  184. package/dist/linter/rules/oxlint-ast.js +104 -0
  185. package/dist/linter/rules/oxlint-ast.js.map +1 -0
  186. package/dist/linter/rules/oxlint-rule.d.ts +45 -0
  187. package/dist/linter/rules/oxlint-rule.d.ts.map +1 -0
  188. package/dist/linter/rules/oxlint-rule.js +2 -0
  189. package/dist/linter/rules/oxlint-rule.js.map +1 -0
  190. package/dist/linter/rules/project-rule.d.ts +10 -0
  191. package/dist/linter/rules/project-rule.d.ts.map +1 -0
  192. package/dist/linter/rules/project-rule.js +24 -0
  193. package/dist/linter/rules/project-rule.js.map +1 -0
  194. package/dist/linter/rules/thin-schema-composition-root.d.ts +3 -0
  195. package/dist/linter/rules/thin-schema-composition-root.d.ts.map +1 -0
  196. package/dist/linter/rules/thin-schema-composition-root.js +23 -0
  197. package/dist/linter/rules/thin-schema-composition-root.js.map +1 -0
  198. package/dist/linter/source.d.ts +24 -0
  199. package/dist/linter/source.d.ts.map +1 -0
  200. package/dist/linter/source.js +279 -0
  201. package/dist/linter/source.js.map +1 -0
  202. package/dist/linter/suppression.d.ts +3 -0
  203. package/dist/linter/suppression.d.ts.map +1 -0
  204. package/dist/linter/suppression.js +11 -0
  205. package/dist/linter/suppression.js.map +1 -0
  206. package/dist/method/class.d.ts +3 -3
  207. package/dist/method/class.d.ts.map +1 -1
  208. package/dist/method/context.d.ts +6 -4
  209. package/dist/method/context.d.ts.map +1 -1
  210. package/dist/method/index.d.ts +5 -5
  211. package/dist/method/index.d.ts.map +1 -1
  212. package/dist/method/index.js +2 -2
  213. package/dist/method/index.js.map +1 -1
  214. package/dist/method/single.d.ts +2 -2
  215. package/dist/method/single.d.ts.map +1 -1
  216. package/dist/server/auxiliary-routes.d.ts +3 -3
  217. package/dist/server/auxiliary-routes.d.ts.map +1 -1
  218. package/dist/server/auxiliary-routes.js +11 -11
  219. package/dist/server/auxiliary-routes.js.map +1 -1
  220. package/dist/server/config.d.ts +1 -1
  221. package/dist/server/config.d.ts.map +1 -1
  222. package/dist/server/create.d.ts +2 -2
  223. package/dist/server/create.d.ts.map +1 -1
  224. package/dist/server/create.js +11 -11
  225. package/dist/server/create.js.map +1 -1
  226. package/dist/server/domain-entry.d.ts +5 -5
  227. package/dist/server/domain-entry.d.ts.map +1 -1
  228. package/dist/server/domain-entry.js +2 -2
  229. package/dist/server/domain-entry.js.map +1 -1
  230. package/dist/server/index.d.ts +11 -11
  231. package/dist/server/index.d.ts.map +1 -1
  232. package/dist/server/index.js +7 -7
  233. package/dist/server/index.js.map +1 -1
  234. package/dist/server/start.d.ts +1 -1
  235. package/dist/server/start.d.ts.map +1 -1
  236. package/dist/server/start.js.map +1 -1
  237. package/dist/server/worker-entry.d.ts +1 -1
  238. package/dist/server/worker-entry.d.ts.map +1 -1
  239. package/dist/server/worker-entry.js +3 -3
  240. package/dist/server/worker-entry.js.map +1 -1
  241. package/dist/step/index.d.ts +4 -4
  242. package/dist/step/index.d.ts.map +1 -1
  243. package/dist/step/index.js +2 -2
  244. package/dist/step/index.js.map +1 -1
  245. package/dist/step/inline.d.ts +1 -1
  246. package/dist/step/inline.d.ts.map +1 -1
  247. package/dist/step/inline.js +1 -1
  248. package/dist/step/inline.js.map +1 -1
  249. package/package.json +29 -8
  250. package/src/auth/authenticate.ts +3 -3
  251. package/src/auth/check.ts +1 -1
  252. package/src/auth/function-context.ts +4 -4
  253. package/src/auth/index.ts +15 -15
  254. package/src/auth/issuer-mint.ts +3 -3
  255. package/src/auth/kernel-client.ts +3 -3
  256. package/src/auth/resolve.ts +4 -4
  257. package/src/auth/verify.ts +3 -3
  258. package/src/cli/bin.ts +1 -1
  259. package/src/cli/index.ts +2 -2
  260. package/src/cli/publish.ts +1 -1
  261. package/src/cli/run.ts +59 -8
  262. package/src/cli/spec.ts +3 -3
  263. package/src/config/define-domain.ts +2 -2
  264. package/src/config/deploy.ts +2 -2
  265. package/src/config/index.ts +6 -6
  266. package/src/define/index.ts +4 -4
  267. package/src/define/remote-function.ts +7 -5
  268. package/src/define/view.ts +3 -3
  269. package/src/deploy/check.ts +2 -2
  270. package/src/deploy/index.ts +2 -2
  271. package/src/dispatch/authorize.ts +1 -1
  272. package/src/dispatch/dispatcher.ts +76 -83
  273. package/src/dispatch/execute.ts +8 -6
  274. package/src/dispatch/identity.ts +2 -2
  275. package/src/dispatch/index.ts +6 -6
  276. package/src/dispatch/resolve.ts +1 -1
  277. package/src/dispatch/self.ts +1 -1
  278. package/src/domain/build-spec.ts +4 -4
  279. package/src/domain/contract.ts +1 -1
  280. package/src/domain/define.ts +6 -6
  281. package/src/domain/extend-functions.ts +2 -2
  282. package/src/domain/extend-views.ts +2 -2
  283. package/src/domain/index.ts +4 -4
  284. package/src/index.ts +20 -20
  285. package/src/linter/analyze.ts +17 -0
  286. package/src/linter/diagnostic.ts +68 -0
  287. package/src/linter/docs/DIAGNOSTICS.md +47 -0
  288. package/src/linter/docs/JUDGMENT.md +81 -0
  289. package/src/linter/docs/PRINCIPLES.md +97 -0
  290. package/src/linter/docs/README.md +38 -0
  291. package/src/linter/docs/RULE-AUTHORING.md +144 -0
  292. package/src/linter/docs/RULES.md +153 -0
  293. package/src/linter/index.ts +14 -0
  294. package/src/linter/lint.ts +32 -0
  295. package/src/linter/oxlint/astrale-ox.d.ts +5 -0
  296. package/src/linter/oxlint/config.ts +19 -0
  297. package/src/linter/oxlint/plugin.js +16 -0
  298. package/src/linter/oxlint/run.ts +162 -0
  299. package/src/linter/preflight.ts +181 -0
  300. package/src/linter/project.ts +108 -0
  301. package/src/linter/report.ts +25 -0
  302. package/src/linter/rules/catalog.ts +67 -0
  303. package/src/linter/rules/core-has-no-async.js +43 -0
  304. package/src/linter/rules/core-is-pure.ts +103 -0
  305. package/src/linter/rules/no-nested-steps.js +37 -0
  306. package/src/linter/rules/no-read-inside-mutate.js +72 -0
  307. package/src/linter/rules/one-remote-definition-per-file.ts +29 -0
  308. package/src/linter/rules/oxlint-ast.js +110 -0
  309. package/src/linter/rules/oxlint-rule.ts +35 -0
  310. package/src/linter/rules/project-rule.ts +37 -0
  311. package/src/linter/rules/thin-schema-composition-root.ts +26 -0
  312. package/src/linter/source.ts +323 -0
  313. package/src/linter/suppression.ts +11 -0
  314. package/src/method/class.ts +3 -3
  315. package/src/method/context.ts +6 -4
  316. package/src/method/index.ts +5 -5
  317. package/src/method/single.ts +2 -2
  318. package/src/server/auxiliary-routes.ts +22 -17
  319. package/src/server/config.ts +1 -1
  320. package/src/server/create.ts +15 -15
  321. package/src/server/domain-entry.ts +7 -7
  322. package/src/server/index.ts +11 -11
  323. package/src/server/start.ts +3 -2
  324. package/src/server/worker-entry.ts +4 -4
  325. package/src/step/index.ts +4 -4
  326. package/src/step/inline.ts +2 -2
  327. package/dist/defer/index.d.ts +0 -24
  328. package/dist/defer/index.d.ts.map +0 -1
  329. package/dist/defer/index.js +0 -42
  330. package/dist/defer/index.js.map +0 -1
  331. package/src/defer/index.ts +0 -64
@@ -0,0 +1,110 @@
1
+ // @ts-check
2
+
3
+ import { relative, sep } from 'node:path'
4
+
5
+ /** @typedef {import('./oxlint-rule.js').AstNode} AstNode */
6
+ /** @typedef {import('./oxlint-rule.js').OxlintRuleContext} OxlintRuleContext */
7
+ /** @typedef {{ object: AstNode, property: string }} StaticMember */
8
+
9
+ /** @param {AstNode | undefined} node @returns {StaticMember | undefined} */
10
+ export function staticMember(node) {
11
+ if (!node || node.type !== 'MemberExpression' || node.computed) return undefined
12
+ if (!node.object || node.property?.type !== 'Identifier' || !node.property.name) return undefined
13
+ return { object: node.object, property: node.property.name }
14
+ }
15
+
16
+ /** @param {AstNode | undefined} node */
17
+ export function isFunctionNode(node) {
18
+ return (
19
+ node?.type === 'ArrowFunctionExpression' ||
20
+ node?.type === 'FunctionDeclaration' ||
21
+ node?.type === 'FunctionExpression'
22
+ )
23
+ }
24
+
25
+ /** @param {AstNode | undefined} node @returns {AstNode | undefined} */
26
+ export function nearestFunction(node) {
27
+ let current = node
28
+ while (current) {
29
+ if (isFunctionNode(current)) return current
30
+ current = current.parent
31
+ }
32
+ return undefined
33
+ }
34
+
35
+ /** @param {AstNode} callback @returns {AstNode | undefined} */
36
+ export function callbackCall(callback) {
37
+ let current = callback
38
+ while (current.parent && isTransparentWrapper(current.parent)) current = current.parent
39
+ const parent = current.parent
40
+ if (parent?.type !== 'CallExpression' || !parent.arguments?.includes(current)) return undefined
41
+ return parent
42
+ }
43
+
44
+ /** @param {AstNode} node */
45
+ function isTransparentWrapper(node) {
46
+ return (
47
+ node.type === 'ChainExpression' ||
48
+ node.type === 'ParenthesizedExpression' ||
49
+ node.type === 'TSAsExpression' ||
50
+ node.type === 'TSNonNullExpression' ||
51
+ node.type === 'TSSatisfiesExpression'
52
+ )
53
+ }
54
+
55
+ /** @param {AstNode | undefined} call */
56
+ export function isStepRun(call) {
57
+ if (call?.type !== 'CallExpression') return false
58
+ const member = staticMember(call.callee)
59
+ if (!member || member.property !== 'run') return false
60
+ if (member.object.type === 'Identifier') return member.object.name === 'step'
61
+ return staticMember(member.object)?.property === 'step'
62
+ }
63
+
64
+ /** @param {AstNode | undefined} call */
65
+ export function isMutateCall(call) {
66
+ if (call?.type !== 'CallExpression') return false
67
+ const member = staticMember(call.callee)
68
+ if (!member || member.property !== 'mutate') return false
69
+ if (member.object.type === 'Identifier') return member.object.name === 'kernel'
70
+ return staticMember(member.object)?.property === 'kernel'
71
+ }
72
+
73
+ /** @param {OxlintRuleContext} context */
74
+ export function relativeFilename(context) {
75
+ const path = relative(context.cwd, context.filename)
76
+ return sep === '/' ? path : path.split(sep).join('/')
77
+ }
78
+
79
+ /** @param {OxlintRuleContext} context */
80
+ export function isProductionFile(context) {
81
+ const path = relativeFilename(context)
82
+ return (
83
+ !path.split('/').includes('__tests__') &&
84
+ !/\.(?:test|spec|bench|perf)\.[cm]?[jt]sx?$/.test(path) &&
85
+ !path.includes('.gen.')
86
+ )
87
+ }
88
+
89
+ /** @param {OxlintRuleContext} context */
90
+ export function isProductionCoreFile(context) {
91
+ const path = relativeFilename(context)
92
+ return (path === 'core' || path.startsWith('core/')) && isProductionFile(context)
93
+ }
94
+
95
+ /** @param {OxlintRuleContext} context @param {AstNode} node @param {string} id @param {string} messageId */
96
+ export function reportUnlessSuppressed(context, node, id, messageId) {
97
+ if (isSuppressed(context, node, id)) return
98
+ context.report({ node, messageId })
99
+ }
100
+
101
+ /** @param {OxlintRuleContext} context @param {AstNode} node @param {string} id */
102
+ function isSuppressed(context, node, id) {
103
+ const line = context.sourceCode.getLoc(node).start.line
104
+ if (line <= 1) return false
105
+ const previous = context.sourceCode.text.split(/\r?\n/)[line - 2]
106
+ const match = previous
107
+ ? /^\s*\/\/\s*astrale-disable-next-line\s+(.+?)\s+--\s+\S.*$/.exec(previous)
108
+ : null
109
+ return match ? match[1].split(/[\s,]+/).includes(id) : false
110
+ }
@@ -0,0 +1,35 @@
1
+ export type AstNode = {
2
+ type: string
3
+ parent?: AstNode
4
+ range?: [number, number]
5
+ async?: boolean
6
+ await?: boolean
7
+ name?: string
8
+ computed?: boolean
9
+ object?: AstNode
10
+ property?: AstNode
11
+ callee?: AstNode
12
+ arguments?: AstNode[]
13
+ }
14
+
15
+ export type OxlintRuleContext = {
16
+ id: string
17
+ filename: string
18
+ cwd: string
19
+ sourceCode: {
20
+ text: string
21
+ getText(node?: AstNode | null): string
22
+ getLoc(node: AstNode): { start: { line: number; column: number } }
23
+ }
24
+ report(diagnostic: { node: AstNode; messageId: string }): void
25
+ }
26
+
27
+ export type OxlintRule = {
28
+ meta: {
29
+ type: 'problem'
30
+ docs: { description: string; url: string }
31
+ messages: Record<string, string>
32
+ schema: readonly []
33
+ }
34
+ create(context: OxlintRuleContext): Record<string, ((node: AstNode) => void) | undefined>
35
+ }
@@ -0,0 +1,37 @@
1
+ import type { LintDiagnostic } from '../diagnostic.js'
2
+ import type { DomainProject } from '../project.js'
3
+ import type { SourceFile, SourceToken } from '../source.js'
4
+
5
+ import { isSuppressed } from '../suppression.js'
6
+ import { ruleCatalog, ruleId, type ImplementedRuleSlug } from './catalog.js'
7
+
8
+ export type AnalyzerRule = {
9
+ slug: ImplementedRuleSlug
10
+ analyze(project: DomainProject): readonly LintDiagnostic[]
11
+ }
12
+
13
+ export function analyzerDiagnostic(
14
+ slug: ImplementedRuleSlug,
15
+ file: SourceFile,
16
+ token: SourceToken,
17
+ detail?: string,
18
+ ): LintDiagnostic | undefined {
19
+ const info = ruleCatalog[slug]
20
+ const id = ruleId(slug)
21
+ if (isSuppressed(file, token.line, id)) return undefined
22
+ return {
23
+ id,
24
+ severity: 'error',
25
+ message: detail ? `${info.message} ${detail}` : info.message,
26
+ help: info.help,
27
+ url: info.url,
28
+ owner: info.owner,
29
+ location: {
30
+ path: file.relativePath,
31
+ line: token.line,
32
+ column: token.column,
33
+ offset: token.offset,
34
+ length: token.length,
35
+ },
36
+ }
37
+ }
@@ -0,0 +1,26 @@
1
+ import type { LintDiagnostic } from '../diagnostic.js'
2
+ import type { DomainProject } from '../project.js'
3
+
4
+ import { importedCalls } from '../source.js'
5
+ import { analyzerDiagnostic, type AnalyzerRule } from './project-rule.js'
6
+
7
+ const schemaModules = new Set(['@astrale-os/kernel-core', '@astrale-os/kernel-dsl'])
8
+ const memberConstructors = new Set([
9
+ 'edgeClass',
10
+ 'edgeInterface',
11
+ 'fn',
12
+ 'func',
13
+ 'nodeClass',
14
+ 'nodeInterface',
15
+ ])
16
+
17
+ export const thinSchemaCompositionRoot: AnalyzerRule = {
18
+ slug: 'thin-schema-composition-root',
19
+ analyze(project: DomainProject): readonly LintDiagnostic[] {
20
+ const root = project.files.find((file) => file.relativePath === 'schema/index.ts')
21
+ if (!root) return []
22
+ return importedCalls(root, schemaModules, memberConstructors)
23
+ .map((token) => analyzerDiagnostic(this.slug, root, token, `Found ${token.value}().`))
24
+ .filter((diagnostic): diagnostic is LintDiagnostic => diagnostic !== undefined)
25
+ },
26
+ }
@@ -0,0 +1,323 @@
1
+ export type SourceToken = {
2
+ kind: 'identifier' | 'string' | 'punctuation'
3
+ value: string
4
+ offset: number
5
+ length: number
6
+ line: number
7
+ column: number
8
+ }
9
+
10
+ export type SourceImport = {
11
+ specifier: string
12
+ token: SourceToken
13
+ bindings: ReadonlyMap<string, string>
14
+ namespace?: string
15
+ }
16
+
17
+ export type SourceFile = {
18
+ path: string
19
+ relativePath: string
20
+ text: string
21
+ tokens: readonly SourceToken[]
22
+ imports: readonly SourceImport[]
23
+ }
24
+
25
+ const identifierStart = /[A-Za-z_$]/
26
+ const identifierPart = /[A-Za-z0-9_$]/
27
+
28
+ export function scanSource(path: string, relativePath: string, text: string): SourceFile {
29
+ const tokens = tokenize(text)
30
+ return { path, relativePath, text, tokens, imports: parseImports(tokens) }
31
+ }
32
+
33
+ function tokenize(text: string): SourceToken[] {
34
+ const tokens: SourceToken[] = []
35
+ let offset = 0
36
+ let line = 1
37
+ let column = 1
38
+
39
+ const advance = (): string => {
40
+ const char = text[offset++]!
41
+ if (char === '\n') {
42
+ line++
43
+ column = 1
44
+ } else {
45
+ column++
46
+ }
47
+ return char
48
+ }
49
+
50
+ while (offset < text.length) {
51
+ const char = text[offset]!
52
+ if (/\s/.test(char)) {
53
+ advance()
54
+ continue
55
+ }
56
+
57
+ if (char === '/' && text[offset + 1] === '/') {
58
+ advance()
59
+ advance()
60
+ while (offset < text.length && text[offset] !== '\n') advance()
61
+ continue
62
+ }
63
+
64
+ if (char === '/' && text[offset + 1] === '*') {
65
+ advance()
66
+ advance()
67
+ while (offset < text.length) {
68
+ if (text[offset] === '*' && text[offset + 1] === '/') {
69
+ advance()
70
+ advance()
71
+ break
72
+ }
73
+ advance()
74
+ }
75
+ continue
76
+ }
77
+
78
+ if (char === "'" || char === '"') {
79
+ const quote = char
80
+ const start = offset
81
+ const startLine = line
82
+ const startColumn = column
83
+ advance()
84
+ let value = ''
85
+ while (offset < text.length) {
86
+ const current = advance()
87
+ if (current === '\\') {
88
+ if (offset < text.length) value += decodeEscape(advance())
89
+ continue
90
+ }
91
+ if (current === quote) break
92
+ value += current
93
+ }
94
+ tokens.push({
95
+ kind: 'string',
96
+ value,
97
+ offset: start,
98
+ length: offset - start,
99
+ line: startLine,
100
+ column: startColumn,
101
+ })
102
+ continue
103
+ }
104
+
105
+ if (char === '`') {
106
+ advance()
107
+ while (offset < text.length) {
108
+ const current = advance()
109
+ if (current === '\\') {
110
+ if (offset < text.length) advance()
111
+ continue
112
+ }
113
+ if (current === '`') break
114
+ }
115
+ continue
116
+ }
117
+
118
+ if (identifierStart.test(char)) {
119
+ const start = offset
120
+ const startLine = line
121
+ const startColumn = column
122
+ let value = advance()
123
+ while (offset < text.length && identifierPart.test(text[offset]!)) value += advance()
124
+ tokens.push({
125
+ kind: 'identifier',
126
+ value,
127
+ offset: start,
128
+ length: offset - start,
129
+ line: startLine,
130
+ column: startColumn,
131
+ })
132
+ continue
133
+ }
134
+
135
+ tokens.push({
136
+ kind: 'punctuation',
137
+ value: char,
138
+ offset,
139
+ length: 1,
140
+ line,
141
+ column,
142
+ })
143
+ advance()
144
+ }
145
+
146
+ return tokens
147
+ }
148
+
149
+ function decodeEscape(char: string): string {
150
+ switch (char) {
151
+ case 'n':
152
+ return '\n'
153
+ case 'r':
154
+ return '\r'
155
+ case 't':
156
+ return '\t'
157
+ default:
158
+ return char
159
+ }
160
+ }
161
+
162
+ function parseImports(tokens: readonly SourceToken[]): SourceImport[] {
163
+ const imports: SourceImport[] = []
164
+ for (let index = 0; index < tokens.length; index++) {
165
+ const token = tokens[index]!
166
+ if (token.kind !== 'identifier' || (token.value !== 'import' && token.value !== 'export')) {
167
+ continue
168
+ }
169
+
170
+ if (token.value === 'import' && tokens[index + 1]?.value === '(') {
171
+ const specifier = tokens[index + 2]
172
+ if (specifier?.kind === 'string') {
173
+ imports.push({ specifier: specifier.value, token, bindings: new Map() })
174
+ }
175
+ continue
176
+ }
177
+
178
+ const end = statementEnd(tokens, index + 1)
179
+ let specifierIndex = -1
180
+ for (let cursor = index + 1; cursor < end; cursor++) {
181
+ const candidate = tokens[cursor]!
182
+ if (candidate.kind === 'string') specifierIndex = cursor
183
+ }
184
+ if (specifierIndex < 0) continue
185
+
186
+ const specifier = tokens[specifierIndex]!
187
+ const bindings = new Map<string, string>()
188
+ let namespace: string | undefined
189
+ if (token.value === 'import') {
190
+ const fromIndex = findToken(tokens, index + 1, specifierIndex, 'from')
191
+ const bindingsEnd = fromIndex >= 0 ? fromIndex : specifierIndex
192
+ const open = findToken(tokens, index + 1, bindingsEnd, '{')
193
+ if (open >= 0) {
194
+ const close = findMatching(tokens, open, '{', '}', bindingsEnd)
195
+ if (close >= 0) parseNamedBindings(tokens, open + 1, close, bindings)
196
+ }
197
+ const star = findToken(tokens, index + 1, bindingsEnd, '*')
198
+ if (star >= 0 && tokens[star + 1]?.value === 'as') namespace = tokens[star + 2]?.value
199
+ }
200
+
201
+ imports.push({
202
+ specifier: specifier.value,
203
+ token,
204
+ bindings,
205
+ ...(namespace ? { namespace } : {}),
206
+ })
207
+ index = Math.max(index, specifierIndex)
208
+ }
209
+ return imports
210
+ }
211
+
212
+ function statementEnd(tokens: readonly SourceToken[], start: number): number {
213
+ let depth = 0
214
+ let sawSpecifier = false
215
+ for (let index = start; index < tokens.length; index++) {
216
+ const token = tokens[index]!
217
+ if (token.value === ';' && depth === 0) return index
218
+ if (token.value === '{' || token.value === '(' || token.value === '[') depth++
219
+ if (token.value === '}' || token.value === ')' || token.value === ']') depth--
220
+ if (token.kind === 'string' && depth === 0) sawSpecifier = true
221
+ const next = tokens[index + 1]
222
+ if (sawSpecifier && depth === 0 && next && next.line > token.line) return index + 1
223
+ }
224
+ return tokens.length
225
+ }
226
+
227
+ function findToken(
228
+ tokens: readonly SourceToken[],
229
+ start: number,
230
+ end: number,
231
+ value: string,
232
+ ): number {
233
+ for (let index = start; index < end; index++) {
234
+ if (tokens[index]?.value === value) return index
235
+ }
236
+ return -1
237
+ }
238
+
239
+ function findMatching(
240
+ tokens: readonly SourceToken[],
241
+ start: number,
242
+ open: string,
243
+ close: string,
244
+ end: number,
245
+ ): number {
246
+ let depth = 0
247
+ for (let index = start; index < end; index++) {
248
+ if (tokens[index]?.value === open) depth++
249
+ if (tokens[index]?.value === close && --depth === 0) return index
250
+ }
251
+ return -1
252
+ }
253
+
254
+ function parseNamedBindings(
255
+ tokens: readonly SourceToken[],
256
+ start: number,
257
+ end: number,
258
+ bindings: Map<string, string>,
259
+ ): void {
260
+ let index = start
261
+ while (index < end) {
262
+ if (tokens[index]?.value === ',' || tokens[index]?.value === 'type') {
263
+ index++
264
+ continue
265
+ }
266
+ const imported = tokens[index]
267
+ if (!imported || imported.kind !== 'identifier') {
268
+ index++
269
+ continue
270
+ }
271
+ if (tokens[index + 1]?.value === 'as' && tokens[index + 2]?.kind === 'identifier') {
272
+ bindings.set(imported.value, tokens[index + 2]!.value)
273
+ index += 3
274
+ continue
275
+ }
276
+ bindings.set(imported.value, imported.value)
277
+ index++
278
+ }
279
+ }
280
+
281
+ export function importedCalls(
282
+ file: SourceFile,
283
+ modules: ReadonlySet<string>,
284
+ names: ReadonlySet<string>,
285
+ ): SourceToken[] {
286
+ const locals = new Set<string>()
287
+ const namespaces = new Set<string>()
288
+ for (const sourceImport of file.imports) {
289
+ if (!modules.has(sourceImport.specifier)) continue
290
+ for (const name of names) {
291
+ const local = sourceImport.bindings.get(name)
292
+ if (local) locals.add(local)
293
+ }
294
+ if (sourceImport.namespace) namespaces.add(sourceImport.namespace)
295
+ }
296
+
297
+ const calls: SourceToken[] = []
298
+ for (let index = 0; index < file.tokens.length; index++) {
299
+ const token = file.tokens[index]!
300
+ if (token.kind !== 'identifier') continue
301
+ if (locals.has(token.value) && callFollows(file.tokens, index)) {
302
+ calls.push(token)
303
+ continue
304
+ }
305
+ if (
306
+ namespaces.has(token.value) &&
307
+ file.tokens[index + 1]?.value === '.' &&
308
+ names.has(file.tokens[index + 2]?.value ?? '') &&
309
+ callFollows(file.tokens, index + 2)
310
+ ) {
311
+ calls.push(file.tokens[index + 2]!)
312
+ }
313
+ }
314
+ return calls
315
+ }
316
+
317
+ function callFollows(tokens: readonly SourceToken[], index: number): boolean {
318
+ const next = tokens[index + 1]
319
+ if (next?.value === '(') return true
320
+ if (next?.value !== '<') return false
321
+ const close = findMatching(tokens, index + 1, '<', '>', tokens.length)
322
+ return close >= 0 && tokens[close + 1]?.value === '('
323
+ }
@@ -0,0 +1,11 @@
1
+ import type { SourceFile } from './source.js'
2
+
3
+ const suppression = /^\s*\/\/\s*astrale-disable-next-line\s+(.+?)\s+--\s+\S.*$/
4
+
5
+ export function isSuppressed(file: SourceFile, line: number, id: string): boolean {
6
+ if (line <= 1) return false
7
+ const previous = file.text.split(/\r?\n/)[line - 2]
8
+ const match = previous ? suppression.exec(previous) : null
9
+ if (!match) return false
10
+ return match[1]!.split(/[\s,]+/).includes(id)
11
+ }
@@ -25,9 +25,9 @@ import type {
25
25
  } from '@astrale-os/kernel-core/domain'
26
26
  import type { ImplementableOwnKeys, Schema } from '@astrale-os/kernel-dsl'
27
27
 
28
- import type { TypedSelf } from '../dispatch/self'
29
- import type { DomainKernel } from './context'
30
- import type { MethodImpl, RemoteHandler } from './single'
28
+ import type { TypedSelf } from '../dispatch/self.js'
29
+ import type { DomainKernel } from './context.js'
30
+ import type { MethodImpl, RemoteHandler } from './single.js'
31
31
 
32
32
  /** Per-class method implementations for a remote domain. */
33
33
  export type ClassMethodsImpl<
@@ -13,11 +13,11 @@ import type { FnMap, SchemaBoundView } from '@astrale-os/kernel-client'
13
13
  import type { BoundClientSessionView } from '@astrale-os/kernel-client/session'
14
14
  import type { AuthContext } from '@astrale-os/kernel-core'
15
15
  import type { Schema } from '@astrale-os/kernel-dsl'
16
+ import type { Defer, Sleep } from '@astrale-os/kernel-server'
16
17
 
17
- import type { FunctionContextApi } from '../auth/function-context'
18
- import type { DomainAuthority } from '../auth/issuer-mint'
19
- import type { Defer } from '../defer'
20
- import type { Step } from '../step'
18
+ import type { FunctionContextApi } from '../auth/function-context.js'
19
+ import type { DomainAuthority } from '../auth/issuer-mint.js'
20
+ import type { Step } from '../step/index.js'
21
21
 
22
22
  export type { GraphApi } from '@astrale-os/kernel-client/graph'
23
23
 
@@ -130,4 +130,6 @@ export interface RemoteContext<
130
130
  step: Step
131
131
  /** Run independent work without making its completion part of this result. */
132
132
  defer: Defer
133
+ /** Pause execution for a relative duration. Durable hosts may persist the wait. */
134
+ sleep: Sleep
133
135
  }
@@ -6,14 +6,14 @@ export type {
6
6
  KernelForAuth,
7
7
  RemoteAuthorizeContext,
8
8
  RemoteContext,
9
- } from './context'
9
+ } from './context.js'
10
10
  export type {
11
11
  RemoteHandler,
12
12
  AnyRemoteHandler,
13
13
  MethodImpl,
14
14
  MethodParams,
15
15
  MethodResult,
16
- } from './single'
17
- export { remoteMethod } from './single'
18
- export type { ClassMethodsImpl, InterfaceMethodsImpl, SchemaMethodsImpl } from './class'
19
- export { remoteClassMethods, remoteInterfaceMethods } from './class'
16
+ } from './single.js'
17
+ export { remoteMethod } from './single.js'
18
+ export type { ClassMethodsImpl, InterfaceMethodsImpl, SchemaMethodsImpl } from './class.js'
19
+ export { remoteClassMethods, remoteInterfaceMethods } from './class.js'
@@ -9,14 +9,14 @@ import type {
9
9
  } from '@astrale-os/kernel-core/domain'
10
10
  import type { Schema } from '@astrale-os/kernel-dsl'
11
11
 
12
- import type { TypedSelf } from '../dispatch/self'
12
+ import type { TypedSelf } from '../dispatch/self.js'
13
13
  import type {
14
14
  DomainKernel,
15
15
  Kernel,
16
16
  KernelForAuth,
17
17
  RemoteAuthorizeContext,
18
18
  RemoteContext,
19
- } from './context'
19
+ } from './context.js'
20
20
 
21
21
  /**
22
22
  * Remote method handler. `execute` is optional only for binding stubs; any
@@ -36,21 +36,25 @@ import {
36
36
  type FunctionBinding,
37
37
  type AuthPolicy,
38
38
  } from '@astrale-os/kernel-api/routed'
39
- import { buildCorsHeaders, type CorsConfig } from '@astrale-os/kernel-server'
40
-
41
- import type { RemoteIdentityConfig } from '../auth/identity'
42
- import type { AnyRemoteFunctionDef } from '../define/remote-function'
43
- import type { ViewDef } from '../define/view'
44
- import type { AuxIdentityMap } from '../dispatch/identity'
45
-
46
- import { makeFunctionContext } from '../auth/function-context'
47
- import { makeDomainAuthority } from '../auth/issuer-mint'
48
- import { resolveInboundAuth } from '../auth/resolve'
49
- import { createHandlerLifecycle, executionLifetime } from '../defer'
50
- import { runAuthorize } from '../dispatch/authorize'
51
- import { SdkResultValidationError, SdkValidationError } from '../dispatch/errors'
52
- import { validateParams, validateResult } from '../dispatch/validate'
53
- import { createInlineStep } from '../step'
39
+ import {
40
+ buildCorsHeaders,
41
+ createCapabilityLifecycle,
42
+ honoCapabilityHost,
43
+ type CorsConfig,
44
+ } from '@astrale-os/kernel-server'
45
+
46
+ import type { RemoteIdentityConfig } from '../auth/identity.js'
47
+ import type { AnyRemoteFunctionDef } from '../define/remote-function.js'
48
+ import type { ViewDef } from '../define/view.js'
49
+ import type { AuxIdentityMap } from '../dispatch/identity.js'
50
+
51
+ import { makeFunctionContext } from '../auth/function-context.js'
52
+ import { makeDomainAuthority } from '../auth/issuer-mint.js'
53
+ import { resolveInboundAuth } from '../auth/resolve.js'
54
+ import { runAuthorize } from '../dispatch/authorize.js'
55
+ import { SdkResultValidationError, SdkValidationError } from '../dispatch/errors.js'
56
+ import { validateParams, validateResult } from '../dispatch/validate.js'
57
+ import { createInlineStep } from '../step/index.js'
54
58
 
55
59
  export type AuxiliaryRoutesConfig<TDeps> = {
56
60
  app: Hono
@@ -172,7 +176,7 @@ export function mountAuxiliaryRoutes<TDeps>(config: AuxiliaryRoutesConfig<TDeps>
172
176
  }),
173
177
  }
174
178
  if (def.authorize) await runAuthorize(def.authorize, ctx)
175
- const lifecycle = createHandlerLifecycle(executionLifetime(c))
179
+ const lifecycle = createCapabilityLifecycle(honoCapabilityHost(c))
176
180
  const result = await (async () => {
177
181
  try {
178
182
  return await def.execute({
@@ -180,7 +184,8 @@ export function mountAuxiliaryRoutes<TDeps>(config: AuxiliaryRoutesConfig<TDeps>
180
184
  step: createInlineStep({
181
185
  scope: { kind: 'function', ref: `function.${slug}`, slug },
182
186
  }),
183
- defer: lifecycle.defer,
187
+ defer: lifecycle.capabilities.defer,
188
+ sleep: lifecycle.capabilities.sleep,
184
189
  })
185
190
  } finally {
186
191
  await lifecycle.settle()